{"record":{"id":"1c41198f302b9e06","repo":"jstedfast/MailKit","slug":"control-characters-are-prohibited","errorCode":null,"errorMessage":"Control characters are prohibited.","messagePattern":"Control characters are prohibited\\.","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"MailKit/Security/SaslMechanism.cs","lineNumber":742,"sourceCode":"\t\tpublic static string SaslPrep (string s)\n\t\t{\n\t\t\tif (s == null)\n\t\t\t\tthrow new ArgumentNullException (nameof (s));\n\n\t\t\tif (s.Length == 0)\n\t\t\t\treturn s;\n\n\t\t\tvar builder = new StringBuilder (s.Length);\n\t\t\tfor (int i = 0; i < s.Length; i++) {\n\t\t\t\tif (IsNonAsciiSpace (s[i])) {\n\t\t\t\t\t// non-ASCII space characters [StringPrep, C.1.2] that can be\n\t\t\t\t\t// mapped to SPACE (U+0020).\n\t\t\t\t\tbuilder.Append (' ');\n\t\t\t\t} else if (IsCommonlyMappedToNothing (s[i])) {\n\t\t\t\t\t// the \"commonly mapped to nothing\" characters [StringPrep, B.1]\n\t\t\t\t\t// that can be mapped to nothing.\n\t\t\t\t} else if (char.IsControl (s[i])) {\n\t\t\t\t\tthrow new ArgumentException (\"Control characters are prohibited.\", nameof (s));\n\t\t\t\t} else if (IsProhibited (s, i)) {\n\t\t\t\t\tthrow new ArgumentException (\"One or more characters in the string are prohibited.\", nameof (s));\n\t\t\t\t} else {\n\t\t\t\t\tbuilder.Append (s[i]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn builder.ToString ().Normalize (NormalizationForm.FormKC);\n\t\t}\n\n\t\tinternal static string GenerateEntropy (int n)\n\t\t{\n\t\t\tvar entropy = new byte[n];\n\n\t\t\tusing (var rng = RandomNumberGenerator.Create ())\n\t\t\t\trng.GetBytes (entropy);\n\n\t\t\treturn Convert.ToBase64String (entropy);","sourceCodeStart":724,"sourceCodeEnd":760,"githubUrl":"https://github.com/jstedfast/MailKit/blob/9d3859a7855e3e17582c07fd01972b8e262bf176/MailKit/Security/SaslMechanism.cs#L724-L760","documentation":"SaslMechanism.SaslPrep normalizes user strings per RFC 4013 (SASLprep). Control characters (U+0000-U+001F, U+007F) are prohibited in SASLprep output, so the method throws ArgumentException when the input string contains one. The library rejects the value early rather than sending an invalid identity to the server.","triggerScenarios":"Passing a username, authorization id, or other SASL identity containing control characters (e.g. a stray \\0, \\t, \\r, or \\n, often from config files or copy-paste) to a SaslMechanism constructor or credential property that runs SaslPrep.","commonSituations":"Credentials loaded from files with trailing newlines/CR, usernames read from environment variables or databases containing NUL bytes, passwords pasted from terminals with embedded control codes.","solutions":["Trim and strip control characters from the string before passing it to the SASL mechanism (e.g. new string(s.Where(c => !char.IsControl(c)).ToArray())).","Fix the source of the string (config file, env var, DB) so it does not include control characters, e.g. use .Trim() on values read from files.","Catch ArgumentException and surface a clear 'invalid username/password' message to the user."],"exampleFix":"// before\nvar mech = new SaslMechanismLogin(userName); // userName contains \"alice\\n\"\n// after\nvar clean = new string(userName.Where(c => !char.IsControl(c)).ToArray()).Trim();\nvar mech = new SaslMechanismLogin(clean);","handlingStrategy":"validation","validationCode":"static string SanitizeSaslString(string s) {\n    if (s == null) throw new ArgumentNullException(nameof(s));\n    var clean = new string(s.Where(c => !char.IsControl(c)).ToArray()).Trim();\n    return clean.Normalize(NormalizationForm.FormKC);\n}\nvar mech = new SaslMechanismLogin(SanitizeSaslString(userName));","typeGuard":null,"tryCatchPattern":"try {\n    var mech = new SaslMechanismLogin(userName);\n} catch (ArgumentException) {\n    // reject credential: contains control/prohibited characters\n}","preventionTips":["Trim all credential values read from files, env vars, or databases","Strip char.IsControl characters before constructing SASL mechanisms","Normalize user input with FormKC before authentication"],"tags":["sasl","argument-validation","encoding"],"backgroundTag":"invalid-argument-value","analyzedSha":"9d3859a7855e3e17582c07fd01972b8e262bf176","analyzedAt":"2026-09-15T15:46:11.592Z","contentChangedAt":"2026-09-15T15:46:11.592Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}