{"record":{"id":"0c21d21ef1c6abe1","repo":"larksuite/cli","slug":"emlbuilder-header-value-contains-control-characte","errorCode":null,"errorMessage":"emlbuilder: header value contains control character: %q","messagePattern":"emlbuilder: header value contains control character: %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shortcuts/mail/emlbuilder/builder.go","lineNumber":140,"sourceCode":"\tcontentType string\n\tfileName    string\n\tcontentID   string // without angle brackets\n\tisOtherPart bool   // true = no Content-Disposition (AddOtherPart); false = Content-Disposition: inline\n}\n\n// New returns an empty Builder.\nfunc New() Builder {\n\treturn Builder{}\n}\n\n// validateHeaderValue rejects strings that contain characters unsafe in MIME\n// header values: C0 control chars (except \\t for folded headers), DEL (0x7F),\n// and dangerous Unicode (Bidi overrides, zero-width chars) that enable\n// visual-spoofing attacks.\nfunc validateHeaderValue(v string) error {\n\tfor _, r := range v {\n\t\tif r != '\\t' && (r < 0x20 || r == 0x7f) {\n\t\t\treturn fmt.Errorf(\"emlbuilder: header value contains control character: %q\", v) //nolint:forbidigo // intermediate EML builder error; mail command layer wraps into typed ValidationError.\n\t\t}\n\t\tif isHeaderDangerousUnicode(r) {\n\t\t\treturn fmt.Errorf(\"emlbuilder: header value contains dangerous Unicode character: %q\", v) //nolint:forbidigo // intermediate EML builder error; mail command layer wraps into typed ValidationError.\n\t\t}\n\t}\n\treturn nil\n}\n\n// isHeaderDangerousUnicode identifies Unicode code points used for visual\n// spoofing: Bidi overrides that reverse display order, and zero-width characters\n// that hide content.  These must not appear in email header values.\nfunc isHeaderDangerousUnicode(r rune) bool {\n\tswitch {\n\tcase r >= 0x200B && r <= 0x200D: // zero-width space/non-joiner/joiner\n\t\treturn true\n\tcase r == 0xFEFF: // BOM / zero-width no-break space\n\t\treturn true\n\tcase r >= 0x202A && r <= 0x202E: // Bidi: LRE/RLE/PDF/LRO/RLO","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/shortcuts/mail/emlbuilder/builder.go#L122-L158","documentation":"validateHeaderValue screens RFC 2822 header values before they are written into the generated EML, rejecting C0 control characters (except tab, which folded headers allow) and DEL (0x7F) that would corrupt or smuggle header boundaries. The mail command layer later converts this intermediate error into a typed ValidationError.","triggerScenarios":"Calling DispositionNotificationTo, Subject, MessageID, InReplyTo, LMSReplyToMessageID, or References with a value containing raw control bytes — e.g. a subject with embedded \\n or \\r (header injection), a pasted string with stray 0x00-0x1F bytes, or binary noise in a Message-ID.","commonSituations":"User input pasted from terminals or logs carrying ANSI/control characters; subject lines built by concatenating multi-line data; copying Message-IDs out of raw sources with trailing \\r; injection attempts via untrusted subject/reply headers.","solutions":["Strip or sanitize control characters from the header value before setting it","Reject the input at your UI/API boundary with a clear message instead of passing it to the builder","If a newline was intended, fold the header with CRLF+WSP yourself or drop the extra line","Inspect the %q rendering in the error to locate the exact offending byte"],"exampleFix":"// before\nb.Subject(\"Quarterly report\\r\\nBcc: attacker@evil.com\") // header injection\n// after\nclean := strings.Map(func(r rune) rune {\n  if r != '\\t' && (r < 0x20 || r == 0x7f) { return -1 }\n  return r\n}, raw)\nb.Subject(clean)","handlingStrategy":"validation","validationCode":"func sanitizeHeaderValue(v string) string {\n  return strings.Map(func(r rune) rune {\n    if r != '\\t' && (r < 0x20 || r == 0x7f) { return -1 }\n    return r\n  }, v)\n}\nb.Subject(sanitizeHeaderValue(userSubject))","typeGuard":"func isSafeHeaderValue(v string) bool {\n  for _, r := range v {\n    if r != '\\t' && (r < 0x20 || r == 0x7f) { return false }\n  }\n  return true\n}","tryCatchPattern":"err := b.Subject(userSubject)\nif err != nil {\n  if strings.Contains(err.Error(), \"control character\") || strings.Contains(err.Error(), \"dangerous Unicode\") {\n    return fmt.Errorf(\"subject contains invalid characters; sanitize and retry\")\n  }\n  return err\n}","preventionTips":["Strip control chars and dangerous Unicode from user input before setting headers","Never build headers by concatenating raw multi-line data","Reject invalid header input at your UI/API boundary with a clear message","Test with inputs containing \\r\\n and 0x00 bytes to catch injection early"],"tags":["mail","eml-builder","header-validation","header-injection"],"backgroundTag":"invalid-header-value","analyzedSha":"7fd6ef3c07182257ce776cdc5a614e122d5bd4b3","analyzedAt":"2026-09-04T21:17:44.649Z","contentChangedAt":"2026-09-04T21:17:44.649Z","schemaVersion":2},"datasetVersion":"2026-09-12T02:17:10.037Z"}