Skip to content

Reqest headers validation - #1111

Merged
xeioex merged 2 commits into
nginx:masterfrom
xeioex:headers-validation
Aug 14, 2026
Merged

xeioex merged 2 commits into
nginx:masterfrom
xeioex:headers-validation

Conversation

@xeioex

@xeioex xeioex commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

This is more extended fix for problem described in #1109.

xeioex added 2 commits August 13, 2026 16:41
Previously, a property name used to store a response header was copied
into the header list as is, without checking it against the token
grammar, so a name containing control characters produced a malformed
response.

The name is now validated in the two places where it is resolved for a
store: ngx_http_js_ext_header_out() and its QuickJS counterpart, which
also covers Object.defineProperty().  An invalid name is rejected with a
TypeError.

Previously, values assigned to r.headersOut were stored as is, without
checking them for control characters, while ngx_js_check_header_value()
was applied only on the Fetch Headers path.

The conversion of a JS value into a header value is now done by
ngx_js_header_value() and ngx_qjs_header_value(), which validate the
result.  All the r.headersOut store paths, including the special headers
and Content-Type, use them and reject an invalid value with a TypeError.

Reported by vladimirelitokarev@gmail.com.
Previously, for a redirect status ngx_http_send_response() stores the
text passed to r.return() as the Location header value, but the text was
only checked when it was used as a response body, where control
characters are valid.

The text is now validated as a header value for the statuses that turn
it into Location, and is left as is otherwise.
@xeioex
xeioex force-pushed the headers-validation branch from 2fbb3d0 to 023a4dd Compare August 13, 2026 23:41

@VadimZhestikov VadimZhestikov left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good.

Reviewed and tested -- this supersedes #1109, which is now closed.

It catches two things #1109 missed:

  • Header names. #1109 validated values only, so r.headersOut['X\r\nInjected: 1'] = 'v'
    still split the response. Validating where the name is resolved for a store
    covers Object.defineProperty() too.
  • The r.return() redirect target, which reaches Location without ever being
    checked as a header value -- it was only checked as a body, where control
    characters are legal.

The ngx_js_header_value() / ngx_qjs_header_value() wrappers are also a better
shape than what #1109 did. Converting and validating in one call means a store
path cannot pick up the conversion without the check, which is what went wrong
here in the first place.

Coverage looks right: ten call sites across both engines and both nginx version
branches. The one remaining raw ngx_js_string(vm, setval, ...) is in
ngx_http_js_request_variables(), which is not a header path -- correctly left
alone.

Tested on both engines, js_engine qjs and the default:

value CRLF            -> invalid header value
name CRLF             -> invalid header name
Object.defineProperty -> invalid header name
r.return(302, ...)    -> invalid header value

with no injected header appearing in any response, and benign traffic unchanged:
plain values, Location, and Set-Cookie arrays all still work.

One thing that is not yours, but worth knowing: js_shared_dict.t tests 35 and
37 ("foo keys after expire", "no of items in foo after expire") failed in one of
two full-suite runs on this branch. They pass 3 out of 3 when the file is run
alone, and this branch does not touch shared dict code, so it looks like an
expiry test that is timing-sensitive under full-suite load -- the extra tests
here shift the timing. Not attributable to this change, just flagging it.

@github-project-automation github-project-automation Bot moved this from New to In Review in NGINX OSS Unified Workspace Aug 14, 2026
@xeioex
xeioex merged commit 2ca3f08 into nginx:master Aug 14, 2026
2 checks passed
@github-project-automation github-project-automation Bot moved this from In Review to Done in NGINX OSS Unified Workspace Aug 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants