{"record":{"id":"9be415600df0dc60","repo":"gravitational/teleport","slug":"special-character-q-not-quoted-s","errorCode":null,"errorMessage":"special character %q not quoted: %s","messagePattern":"special character %q not quoted: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"api/utils/pkixname/parser.go","lineNumber":527,"sourceCode":"\t\tcase tokenizeStateAttrTypeEnd:\n\t\t\tswitch r {\n\t\t\tcase '=':\n\t\t\t\temit(tokenEqual)\n\t\t\t\tstate = tokenizeStateStringStart\n\t\t\tdefault:\n\t\t\t\treturn nil, fmt.Errorf(\"want '=' attributeValue, found %q: %s\", r, errTrace(pos))\n\t\t\t}\n\n\t\tcase tokenizeStateString:\n\t\t\tswitch r {\n\t\t\tcase '+', ',', ';':\n\t\t\t\temitBuffer(tokenString)\n\t\t\t\ttransitionToNameComponent(r)\n\t\t\tcase '\\\\':\n\t\t\t\tescapeStart()\n\t\t\tcase '<', '>', '\"':\n\t\t\t\t// We could '<' and '>', but let's be strict.\n\t\t\t\treturn nil, fmt.Errorf(\"special character %q not quoted: %s\", r, errTrace(pos))\n\t\t\tcase ' ':\n\t\t\t\ttrailingSpaceBuf.WriteRune(r)\n\t\t\t\tstate = tokenizeStateStringEnd\n\t\t\tcase '=', '#': // Go does this.\n\t\t\t\t// NOT OK per RFC, should be escaped.\n\t\t\t\tfallthrough\n\t\t\tdefault:\n\t\t\t\tbuf.WriteRune(r)\n\t\t\t}\n\n\t\tcase tokenizeStateStringEscape:\n\t\t\tswitch r {\n\t\t\tcase ' ': // Go does this.\n\t\t\t\t// OK per RFC and allows the \"\\\\ \" trick.\n\t\t\t\tfallthrough\n\t\t\tcase ',', '=', '+', '<', '>', '#', ';', '\\\\', '\"':\n\t\t\t\tbuf.WriteRune(r)\n\t\t\t\tescapeEnd()","sourceCodeStart":509,"sourceCodeEnd":545,"githubUrl":"https://github.com/gravitational/teleport/blob/1283425b60ec5f60d509ba4c791183d452923ff7/api/utils/pkixname/parser.go#L509-L545","documentation":"RFC 2253 requires the special characters '<', '>', and '\"' to be escaped or inside a quoted string when they appear in an attribute value. This parser is deliberately strict: an unescaped '<', '>', or '\"' in the middle of an unquoted string is a hard error.","triggerScenarios":"Calling ParseDistinguishedName with values containing raw angle brackets or quotes, e.g. \"CN=<Bob>\", \"OU=a\\\"b\", \"O=we<ird\". Note '=' and '#' unescaped in strings also fall through to the same default (appended), but < > \" always error.","commonSituations":"DNs containing XML/HTML-like values such as \"O=<Company>\", copied from tools that auto-quote, or user-supplied names with quotes that were not escaped.","solutions":["Escape the character with a backslash: \"CN=\\\\<Bob\\\\>\".","Wrap the value in double quotes: \"CN=\\\"<Bob>\\\"\" (quotes inside still need escaping).","Strip or replace <, >, \" from user-supplied DN values before parsing."],"exampleFix":"// before\nname, err := pkixname.ParseDistinguishedName(\"CN=<Bob>\")\n// after\nname, err := pkixname.ParseDistinguishedName(\"CN=\\\\<Bob\\\\>\")","handlingStrategy":"validation","validationCode":"func unquotedSpecials(dn string) bool {\n\tinQuotes := false\n\tfor i := 0; i < len(dn); i++ {\n\t\tswitch dn[i] {\n\t\tcase '\\\\':\n\t\t\ti++\n\t\tcase '\"':\n\t\t\tinQuotes = !inQuotes\n\t\tcase '<', '>':\n\t\t\tif !inQuotes {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\treturn false\n}","typeGuard":null,"tryCatchPattern":"name, err := pkixname.ParseDistinguishedName(dn)\nif err != nil {\n\tif strings.Contains(err.Error(), \"special character\") {\n\t\treturn nil, fmt.Errorf(\"DN %q contains unquoted <, > or \\\\\\\"; escape or quote values\", dn)\n\t}\n\treturn nil, err\n}","preventionTips":["Escape <, >, \" with backslash or wrap values in quotes","Sanitize user-supplied organization/common-name values","Reject values containing raw specials at input time"],"tags":["x509","distinguished-name","escaping","parser"],"backgroundTag":"dn-unescaped-special-character","analyzedSha":"1283425b60ec5f60d509ba4c791183d452923ff7","analyzedAt":"2026-09-02T04:06:41.601Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}