{"record":{"id":"0444a7cdce09439e","repo":"git-ecosystem/git-credential-manager","slug":"state-key-cannot-contain-newline-or-nul-char","errorCode":null,"errorMessage":"State key cannot contain '=', newline, or NUL characters.","messagePattern":"State key cannot contain '=', newline, or NUL characters\\.","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Core/GitStateValidation.cs","lineNumber":90,"sourceCode":"        return true;\n    }\n\n    /// <summary>\n    /// Throws <see cref=\"ArgumentException\"/> if <paramref name=\"key\"/> is not\n    /// a legal state entry key.\n    /// </summary>\n    public static void ValidateKey(string key)\n    {\n        if (string.IsNullOrWhiteSpace(key))\n        {\n            throw new ArgumentException(\"State key cannot be null or whitespace.\", nameof(key));\n        }\n\n        foreach (char c in key)\n        {\n            if (c == EQ || c == LF || c == NUL)\n            {\n                throw new ArgumentException(\n                    \"State key cannot contain '=', newline, or NUL characters.\",\n                    nameof(key));\n            }\n        }\n\n        if (key.StartsWith(Constants.CredentialProtocol.GcmStatePrefix, StringComparison.Ordinal))\n        {\n            throw new ArgumentException(\n                $\"State key cannot start with '{Constants.CredentialProtocol.GcmStatePrefix}'; \" +\n                \"the prefix is reserved and added automatically when state is emitted.\",\n                nameof(key));\n        }\n    }\n\n    /// <summary>\n    /// Throws <see cref=\"ArgumentException\"/> if <paramref name=\"value\"/> is\n    /// not a legal state entry value.\n    /// </summary>","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/git-ecosystem/git-credential-manager/blob/e8ce762cd04b4100ae637b5fbf39ef9d0a96561e/src/Core/GitStateValidation.cs#L72-L108","documentation":"State entries are serialized as 'key=value' lines terminated by newlines in the credential-helper protocol. Characters '=', LF, or NUL inside a key would corrupt that framing, so ValidateKey rejects them with ArgumentException.","triggerScenarios":"Calling SetState/WithState with a key containing '=', a newline ('\\n' or '\\r\\n'), or a NUL byte ('\\0').","commonSituations":"Deriving state keys from URLs, error messages, or user data that can embed '=' or line breaks; concatenating key parts without sanitization.","solutions":["Sanitize/encode the key before use, e.g. percent-encode or strip forbidden characters.","Keep state keys to a restricted alphabet (alphanumerics, '-', '_').","Replace '=' inside the key with a safe separator if a composite key is needed."],"exampleFix":"// before\nresponse.SetState($\"provider={providerName}\", value);\n// after\nresponse.SetState($\"provider-{providerName.Replace('=', '_')}\", value);","handlingStrategy":"validation","validationCode":"bool ok = key != null && key.IndexOfAny(new[] {'=', '\\n', '\\r', '\\0'}) < 0;","typeGuard":"static bool IsWireSafeKey(string k) => !string.IsNullOrEmpty(k) && !k.Any(c => c == '=' || c == '\\n' || c == '\\0');","tryCatchPattern":"try { response.SetState(key, value); }\ncatch (ArgumentException e) when (e.Message.Contains(\"cannot contain\")) { key = Sanitize(key); response.SetState(key, value); }","preventionTips":["Restrict state keys to [A-Za-z0-9-_].","Sanitize keys derived from URLs, messages, or user data.","Add a shared SanitizeStateKey helper used everywhere state is set."],"tags":["csharp","validation","protocol-encoding","git-state-protocol"],"backgroundTag":"invalid-argument-format","analyzedSha":"e8ce762cd04b4100ae637b5fbf39ef9d0a96561e","analyzedAt":"2026-09-11T17:15:08.753Z","contentChangedAt":"2026-09-11T17:15:08.753Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}