{"record":{"id":"06a2dd79f1af0d10","repo":"FlowiseAI/Flowise","slug":"invalid-header-key-value-contains-illegal-co","errorCode":null,"errorMessage":"Invalid header \"${key}\": value contains illegal control characters","messagePattern":"Invalid header \"(.+?)\": value contains illegal control characters","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/components/src/headerValidation.ts","lineNumber":74,"sourceCode":"        if (!RFC7230_TOKEN.test(key)) {\n            throw new Error(`Invalid header \"${key}\": key contains illegal characters`)\n        }\n\n        const lower = key.toLowerCase()\n        if (DENIED_HEADER_NAMES.has(lower) || DENIED_HEADER_PREFIXES.some((p) => lower.startsWith(p))) {\n            throw new Error(`Invalid header \"${key}\": this header name is not allowed`)\n        }\n\n        if (typeof value !== 'string') {\n            throw new Error(`Invalid header \"${key}\": value must be a string`)\n        }\n        if (value.length > MAX_VALUE_LENGTH) {\n            throw new Error(`Invalid header \"${key}\": value exceeds ${MAX_VALUE_LENGTH} chars`)\n        }\n        for (let i = 0; i < value.length; i++) {\n            const code = value.charCodeAt(i)\n            if (code === 0x0d || code === 0x0a || (code < 0x20 && code !== 0x09)) {\n                throw new Error(`Invalid header \"${key}\": value contains illegal control characters`)\n            }\n        }\n    }\n}\n\n/**\n * Returns a copy of `headers` with credential-bearing entries (Authorization, Cookie, X-Api-Key, …)\n * replaced by a placeholder string. Used at trust boundaries before a header bag is exposed to flow\n * templates, observers, or logs. Comparison is case-insensitive; non-sensitive headers pass through.\n */\nexport function redactSensitiveHeaders(headers: Record<string, any> | undefined | null): Record<string, any> {\n    if (!headers) return {}\n    const out: Record<string, any> = {}\n    for (const [key, value] of Object.entries(headers)) {\n        out[key] = SENSITIVE_HEADER_NAMES.has(key.toLowerCase()) ? REDACTED_PLACEHOLDER : value\n    }\n    return out\n}","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/FlowiseAI/Flowise/blob/abe4a8601a058047b350c260676826e21dd14101/packages/components/src/headerValidation.ts#L56-L92","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nconst headers = { 'X-Trace': errorMessage } // errorMessage may contain '\\n'\nvalidateCustomHeaders(headers)\n\n// after\nconst headers = { 'X-Trace': errorMessage.replace(/[\\r\\n]+/g, ' ').slice(0, 2048) }\nvalidateCustomHeaders(headers)","handlingStrategy":"validation","validationCode":"// Strip CRLF and control chars (keep TAB) before validation\nfunction sanitizeHeaderValue(value: string): string {\n  return value.replace(/[\\r\\n\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]/g, '')\n}\nconst clean = Object.fromEntries(\n  Object.entries(headers).map(([k, v]) => [k, sanitizeHeaderValue(v)])\n)\nvalidateCustomHeaders(clean)","typeGuard":null,"tryCatchPattern":"try {\n  validateCustomHeaders(headers)\n} catch (e) {\n  if (String(e).includes('control characters')) {\n    // re-sanitize and retry once\n    const cleaned = sanitizeAll(headers)\n    validateCustomHeaders(cleaned)\n  } else throw e\n}","preventionTips":["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."],"tags":["security","headers","crlf-injection","validation","http"],"backgroundTag":null,"analyzedSha":"abe4a8601a058047b350c260676826e21dd14101","analyzedAt":"2026-08-12T16:04:40.823Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}