FlowiseAI/Flowise · error · Error
Invalid header "${key}": value contains illegal control char
Error message
Invalid header "${key}": value contains illegal control characters What it means
Thrown by validateCustomHeaders() when a header value contains CR (0x0d), LF (0x0a), or any control character below 0x20 except TAB (0x09). This is a CRLF-injection / response-splitting defense: inserting CR or LF into a header value can terminate the header early and inject a second header or a new response, enabling request smuggling and cache poisoning attacks.
Source
Thrown at packages/components/src/headerValidation.ts:74
if (!RFC7230_TOKEN.test(key)) {
throw new Error(`Invalid header "${key}": key contains illegal characters`)
}
const lower = key.toLowerCase()
if (DENIED_HEADER_NAMES.has(lower) || DENIED_HEADER_PREFIXES.some((p) => lower.startsWith(p))) {
throw new Error(`Invalid header "${key}": this header name is not allowed`)
}
if (typeof value !== 'string') {
throw new Error(`Invalid header "${key}": value must be a string`)
}
if (value.length > MAX_VALUE_LENGTH) {
throw new Error(`Invalid header "${key}": value exceeds ${MAX_VALUE_LENGTH} chars`)
}
for (let i = 0; i < value.length; i++) {
const code = value.charCodeAt(i)
if (code === 0x0d || code === 0x0a || (code < 0x20 && code !== 0x09)) {
throw new Error(`Invalid header "${key}": value contains illegal control characters`)
}
}
}
}
/**
* Returns a copy of `headers` with credential-bearing entries (Authorization, Cookie, X-Api-Key, …)
* replaced by a placeholder string. Used at trust boundaries before a header bag is exposed to flow
* templates, observers, or logs. Comparison is case-insensitive; non-sensitive headers pass through.
*/
export function redactSensitiveHeaders(headers: Record<string, any> | undefined | null): Record<string, any> {
if (!headers) return {}
const out: Record<string, any> = {}
for (const [key, value] of Object.entries(headers)) {
out[key] = SENSITIVE_HEADER_NAMES.has(key.toLowerCase()) ? REDACTED_PLACEHOLDER : value
}
return out
}View on GitHub (pinned to abe4a8601a)
Solutions
- Strip CR/LF and other control characters from user input before placing it in a header: value.replace(/[\r\n\x00-\x1f]\x07|\x08/g, '') (preserve tab if desired).
- URL-encode or base64-encode the value if it legitimately contains newlines.
- Validate the source field at the trust boundary (form/CLI/API input) so control characters never reach the headers builder.
- If the value is structured data, send it in the request body instead.
Example fix
// before
const headers = { 'X-Trace': errorMessage } // errorMessage may contain '\n'
validateCustomHeaders(headers)
// after
const headers = { 'X-Trace': errorMessage.replace(/[\r\n]+/g, ' ').slice(0, 2048) }
validateCustomHeaders(headers) Defensive patterns
Strategy: validation
Validate before calling
// Strip CRLF and control chars (keep TAB) before validation
function sanitizeHeaderValue(value: string): string {
return value.replace(/[\r\n\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, '')
}
const clean = Object.fromEntries(
Object.entries(headers).map(([k, v]) => [k, sanitizeHeaderValue(v)])
)
validateCustomHeaders(clean) Try / catch
try {
validateCustomHeaders(headers)
} catch (e) {
if (String(e).includes('control characters')) {
// re-sanitize and retry once
const cleaned = sanitizeAll(headers)
validateCustomHeaders(cleaned)
} else throw e
} Prevention
- Treat all user input as untrusted; strip control characters at ingestion.
- Never paste raw exception messages or multiline text into header values.
- Add a unit test that feeds CRLF sequences into the header builder.
When it happens
Trigger: A header value containing a literal newline (from a multiline text field), a carriage return, a null byte, or any control character. Common with values sourced from user input, log lines, or templates that embed '\n'. The loop at lines 71-76 scans every char.
Common situations: Pasting multiline text into a header. Forwarding stack traces or log fragments. Values built with template literals that include line breaks. Data read from a file that contains trailing CRLF not stripped. User-supplied metadata that smuggles in control characters.
Related errors
- Invalid header "${key}": this header name is not allowed
- Invalid headers: expected an object
- Invalid headers: too many entries (max ${MAX_HEADERS})
- Invalid header: key must be a non-empty string
- Invalid header "${key}": key exceeds ${MAX_KEY_LENGTH} chars
AI-assisted analysis of FlowiseAI/Flowise@abe4a8601a (2026-08-12).
Data as JSON: /api/errors/06a2dd79f1af0d10.
Report an issue: GitHub.