Skip to content

fix: validate coerced header values for CRLF - #5579

Merged
mcollina merged 1 commit into
mainfrom
fix/header-function-crlf-validation
Jul 22, 2026
Merged

fix: validate coerced header values for CRLF#5579
mcollina merged 1 commit into
mainfrom
fix/header-function-crlf-validation

Conversation

@mcollina

Copy link
Copy Markdown
Member

Why

processHeader() rejected objects but not functions (typeof fn === 'function'). Non-string values were coerced with `${val}` and written to the HTTP/1.1 wire without isValidHeaderValue(), so a function with a crafted toString() / Symbol.toPrimitive could inject CRLF sequences into request headers.

This is defense-in-depth / hardening, not a security advisory under our threat model: exploitation requires the application to pass a function as a header value (trusted application input). String CRLF was already rejected.

Changes

  • After coercing non-string scalar header values, run isValidHeaderValue()
  • Same validation for non-string array elements after coercion
  • Regression tests for toString and Symbol.toPrimitive on scalar and array paths
  • Confirm numbers/booleans still work

Test plan

  • node --test test/header-function-crlf.js test/request-crlf.js test/headers-crlf.js test/invalid-headers.js
  • npm run lint
Functions bypassed the object guard in processHeader() and were
coerced via template literals without isValidHeaderValue(), allowing
CRLF injection when toString/Symbol.toPrimitive returned embedded
newlines. Validate after coercion on both scalar and array paths.

Signed-off-by: Matteo Collina <hello@matteocollina.com>
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.47%. Comparing base (f36ea9c) to head (0a2ae08).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #5579      +/-   ##
==========================================
- Coverage   93.47%   93.47%   -0.01%     
==========================================
  Files         110      110              
  Lines       37564    37575      +11     
==========================================
+ Hits        35114    35122       +8     
- Misses       2450     2453       +3     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
@mcollina
mcollina merged commit 354a151 into main Jul 22, 2026
37 of 38 checks passed
@mcollina
mcollina deleted the fix/header-function-crlf-validation branch July 22, 2026 06:26
mcollina added a commit that referenced this pull request Jul 24, 2026
Functions bypassed the object guard in processHeader() and were
coerced via template literals without isValidHeaderValue(), allowing
CRLF injection when toString/Symbol.toPrimitive returned embedded
newlines. Validate after coercion on both scalar and array paths.

Signed-off-by: Matteo Collina <hello@matteocollina.com>
(cherry picked from commit 354a151)
mcollina added a commit that referenced this pull request Jul 24, 2026
Functions bypassed the object guard in processHeader() and were
coerced via template literals without isValidHeaderValue(), allowing
CRLF injection when toString/Symbol.toPrimitive returned embedded
newlines. Validate after coercion on both scalar and array paths.

Signed-off-by: Matteo Collina <hello@matteocollina.com>
(cherry picked from commit 354a151)
@github-actions github-actions Bot mentioned this pull request Jul 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

4 participants