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

  1. 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).
  2. URL-encode or base64-encode the value if it legitimately contains newlines.
  3. Validate the source field at the trust boundary (form/CLI/API input) so control characters never reach the headers builder.
  4. 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

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


AI-assisted analysis of FlowiseAI/Flowise@abe4a8601a (2026-08-12). Data as JSON: /api/errors/06a2dd79f1af0d10. Report an issue: GitHub.