larksuite/cli · error
emlbuilder: header value contains dangerous Unicode characte
Error message
emlbuilder: header value contains dangerous Unicode character: %q
What it means
The EML builder rejected a header value because it contains a Unicode code point deemed dangerous for RFC 5322 headers (e.g. bidirectional-override or zero-width characters used in spoofing). validateHeaderValue scans every rune of the value and fails fast so a hostile or copy-pasted header can never reach the serialized .eml output. The mail command layer wraps this into a typed ValidationError.
Source
Thrown at shortcuts/mail/emlbuilder/builder.go:143
isOtherPart bool // true = no Content-Disposition (AddOtherPart); false = Content-Disposition: inline
}
// New returns an empty Builder.
func New() Builder {
return Builder{}
}
// validateHeaderValue rejects strings that contain characters unsafe in MIME
// header values: C0 control chars (except \t for folded headers), DEL (0x7F),
// and dangerous Unicode (Bidi overrides, zero-width chars) that enable
// visual-spoofing attacks.
func validateHeaderValue(v string) error {
for _, r := range v {
if r != '\t' && (r < 0x20 || r == 0x7f) {
return fmt.Errorf("emlbuilder: header value contains control character: %q", v) //nolint:forbidigo // intermediate EML builder error; mail command layer wraps into typed ValidationError.
}
if isHeaderDangerousUnicode(r) {
return fmt.Errorf("emlbuilder: header value contains dangerous Unicode character: %q", v) //nolint:forbidigo // intermediate EML builder error; mail command layer wraps into typed ValidationError.
}
}
return nil
}
// isHeaderDangerousUnicode identifies Unicode code points used for visual
// spoofing: Bidi overrides that reverse display order, and zero-width characters
// that hide content. These must not appear in email header values.
func isHeaderDangerousUnicode(r rune) bool {
switch {
case r >= 0x200B && r <= 0x200D: // zero-width space/non-joiner/joiner
return true
case r == 0xFEFF: // BOM / zero-width no-break space
return true
case r >= 0x202A && r <= 0x202E: // Bidi: LRE/RLE/PDF/LRO/RLO
return true
case r >= 0x2028 && r <= 0x2029: // line/paragraph separator
return trueView on GitHub (pinned to 7fd6ef3c07)
Solutions
- Inspect the header value and remove dangerous Unicode characters (RTL overrides U+202A-U+202E, zero-width U+200B-U+200F, etc.).
- Sanitize user-supplied header text before passing it to the builder, stripping or replacing dangerous code points.
- If RTL display is genuinely needed, use explicit language/HTML body formatting instead of Unicode control characters in the header value.
Example fix
// before
b.Subject("lname@bank.com payment")
// after
b.Subject("payment reminder") // dangerous bidi-override characters removed Defensive patterns
Strategy: validation
Validate before calling
var dangerousUnicode = regexp.MustCompile(`[\x{202A}-\x{202E}\x{2066}-\x{2069}\x{200B}-\x{200F}\x{FEFF}]`)
func safeHeaderValue(v string) bool { return !dangerousUnicode.MatchString(v) }
// call before b.Subject(v) / b.MessageID(v) etc. Try / catch
var raw []byte
err := b.Subject(userSubject)
if err != nil {
var verr *ValidationError
if errors.As(err, &verr) {
return fmt.Errorf("subject rejected: %w", verr)
}
return err
} Prevention
- Sanitize all user-supplied header text with a Unicode control/bidi stripper before passing to the builder.
- Never copy-paste subject text from rich-text sources without normalizing (e.g. golang.org/x/text/unicode/norm plus explicit bidi removal).
- Add a unit test asserting your subject templates contain no bidi/zero-width code points.
When it happens
Trigger: Calling Subject, MessageID, InReplyTo, References, DispositionNotificationTo, or LMSReplyToMessageID with a string containing a dangerous Unicode rune (checked by isHeaderDangerousUnicode), e.g. U+202E RIGHT-TO-LEFT OVERRIDE or zero-width characters.
Common situations: Pasting a subject copied from a chat or document that contains invisible/zero-width characters; building localized subjects with RTL overrides for Arabic/Hebrew text; user-supplied subject text from a web form containing spoofing characters.
Related errors
- emlbuilder: header name contains ':', CR, or LF: %q
- emlbuilder: header name contains non-printable character: %q
- emlbuilder: display name contains CR or LF: %q
- emlbuilder: content ID contains control character: %q
- emlbuilder: From address is required
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/27a96c9042ca41ae.
Report an issue: GitHub.