Skip to content

Tests: added proxy CRLF injection tests - #55

Draft
louzt wants to merge 1 commit into
nginx:masterfrom
louzt:test/proxy-crlf-runtime
Draft

Tests: added proxy CRLF injection tests#55
louzt wants to merge 1 commit into
nginx:masterfrom
louzt:test/proxy-crlf-runtime

Conversation

@louzt

@louzt louzt commented May 31, 2026

Copy link
Copy Markdown

Summary

Adds a native nginx-tests regression test for CRLF injection through runtime-expanded variables used while NGINX serializes HTTP/1.x proxy requests.

The test covers:

  • proxy_pass .../$uri, asserting a CRLF-bearing URI is rejected and no injected field reaches the upstream socket;
  • proxy_set_header X-Normalized-URI $uri, asserting CRLF, LF-only, and CR-only values are rejected;
  • raw upstream byte capture, so the check observes what NGINX actually emitted.

Why

This is the narrow runtime proxy boundary discussed in nginx/nginx#590. It intentionally does not change inbound parser policy, config-time validation, or response header/trailer behavior.

The response-filter cases (add_header / add_trailer) are a separate state-machine and policy question, so they are not included in this first test PR. They are covered by nginx-tests#58 alongside the companion nginx#1414.

Validation

Ran locally against a patched NGINX build containing the proxy runtime rejection and log-level slice:

perl -c proxy_crlf_injection.t
TEST_NGINX_BINARY=/path/to/nginx/objs/nginx prove -v proxy_crlf_injection.t

Result:

1..8
ok 1 - proxy_pass uri rejects CRLF
ok 2 - proxy_pass uri does not inject backend header
ok 3 - proxy_set_header rejects CRLF value
ok 4 - proxy_set_header does not inject backend header
ok 5 - proxy_set_header rejects LF value
ok 6 - proxy_set_header rejects CR value
ok 7 - no alerts
ok 8 - no sanitizer errors

Supplementary lab notes and branch matrix: https://gist.github.com/louzt/7bdf370a28126718e7e7b69d53b0ae86

Status

Draft until the matching NGINX core fix in nginx/nginx#1424 (the active H2/H3 reject thread that addresses the broader hardening direction) or its successor lands.

Follow-ups

The response-filter path is intentionally a separate policy PR. nginx-tests#58 covers the add_header / add_trailer companion to nginx#1414 and moves with that core fix.

@louzt
louzt force-pushed the test/proxy-crlf-runtime branch from 9b988cc to af113f3 Compare August 7, 2026 22:30
@louzt

louzt commented Aug 7, 2026

Copy link
Copy Markdown
Author

Rebased onto current master and updated the body to reflect the current proxy runtime boundary scope. The response-filter path is intentionally covered separately by nginx-tests#58 alongside nginx#1414. Lab notes: https://gist.github.com/louzt/7bdf370a28126718e7e7b69d53b0ae86

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: New

Development

Successfully merging this pull request may close these issues.

2 participants