larksuite/cli · error

emlbuilder: header name contains ':', CR, or LF: %q

Error message

emlbuilder: header name contains ':', CR, or LF: %q

What it means

validateHeaderName rejects header names containing ':', CR (\r), or LF (\n), which would break RFC 5322 field-name syntax and could enable header injection. It is enforced when Header() is called so a malformed name never reaches the serialized message. Wrapped into a typed ValidationError by the mail command layer.

Source

Thrown at shortcuts/mail/emlbuilder/builder.go:172

	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 true
	case r >= 0x2066 && r <= 0x2069: // Bidi isolates: LRI/RLI/FSI/PDI
		return true
	}
	return false
}

// validateHeaderName rejects any string that contains ':', CR (\r), LF (\n),
// or non-printable ASCII characters, as required by RFC 5322 field-name syntax.
func validateHeaderName(n string) error {
	if strings.ContainsAny(n, ":\r\n") {
		return fmt.Errorf("emlbuilder: header name contains ':', CR, or LF: %q", n) //nolint:forbidigo // intermediate EML builder error; mail command layer wraps into typed ValidationError.
	}
	for _, r := range n {
		if r < 0x21 || r > 0x7e {
			return fmt.Errorf("emlbuilder: header name contains non-printable character: %q", n) //nolint:forbidigo // intermediate EML builder error; mail command layer wraps into typed ValidationError.
		}
	}
	return nil
}

// validateDisplayName rejects display names containing CR or LF, which could
// escape the quoted-string encoding used by mail.Address.String() and inject headers.
func validateDisplayName(name string) error {
	if strings.ContainsAny(name, "\r\n") {
		return fmt.Errorf("emlbuilder: display name contains CR or LF: %q", name) //nolint:forbidigo // intermediate EML builder error; mail command layer wraps into typed ValidationError.
	}
	return nil
}

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Remove ':' / CR / LF from the header name; pass only the bare field name to Header().
  2. Split any 'Name: value' string at the first ':' and pass the two halves as separate arguments.
  3. Trim/normalize the name with strings.TrimSpace and validate it is printable ASCII before calling Header().

Example fix

// before
b.Header("X-Custom: " + value, value)
// after
b.Header("X-Custom", value)
Defensive patterns

Strategy: validation

Validate before calling

func safeHeaderName(n string) bool {
    if strings.ContainsAny(n, ":\r\n") { return false }
    for _, r := range n {
        if r < 0x21 || r > 0x7e { return false }
    }
    return len(n) > 0
}
// check before b.Header(name, value)

Try / catch

if err := b.Header(name, value); err != nil {
    var verr *ValidationError
    if errors.As(err, &verr) { /* surface to caller with the offending name */ }
    return err
}

Prevention

When it happens

Trigger: Calling Builder.Header with a name string containing ':', '\r', or '\n' — e.g. Header("X-Foo: injected", ...) or a name built from user input that includes a newline.

Common situations: Concatenating 'name: value' into one string and passing it as the name; user-controlled header names from a web form; CRLF accidentally included when reading names from config files or CSV.

Related errors


AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04). Data as JSON: /api/errors/dedaefac67ca1aaa. Report an issue: GitHub.