
Scan your NGINX configuration to determine whether it is affected by CVE-2026-42945.
Static scanner for NGINX configuration files that detects the rewrite/set pattern associated with CVE-2026-42945.
The scanner parses NGINX configs with
crossplane, walks location blocks,
and prints every location that looks affected in this format:
/<path-to>/xxx.conf:<line-number> -> location XXXXX
Example:
/path/to/nginx.conf:39 -> location ~ ^/api/(.*)$
Reference: CVE-2026-42945-POC.
Dependencies are managed with uv in pyproject.toml and locked in uv.lock.
The only runtime dependency is .
crossplaneFrom the repository root:
uv sync
You can also skip a separate setup step and let uv run create the environment
on first use.
Scan one config file:
uv run ./scan.py /etc/nginx/nginx.conf
Scan a directory recursively:
uv run ./scan.py -r /etc/nginx
Scan recursively from the current directory for *.conf files:
uv run ./scan.py -r './*.conf'
Quote globs when you want the scanner to expand them recursively. If your shell
expands ./*.conf first, the scanner receives only the files matched by the
shell.
Scan only the provided files and do not follow include directives:
uv run ./scan.py --single ./site.conf
Show parser warnings, including missing include files:
uv run ./scan.py -v -r /etc/nginx
A Go implementation with the same output format and exit codes is available in
go/. It uses
nginx-go-crossplane for NGINX
config parsing and pflag for CLI flags.
It requires Go 1.23 or newer.
Run it with go run:
cd go
go run . -r ../tests/fixtures
When findings are present, the scanner exits with code 1. go run will print
an extra exit status 1 line for that case; build the binary when you want only
the scanner output.
Build a standalone binary:
cd go
go build -o cve-2026-42945-scan-go .
./cve-2026-42945-scan-go -r ../tests/fixtures
The risky configuration pattern is a location that contains:
rewrite directive whose replacement contains an unescaped ?last, break, redirect, or permanentset directive that copies a regex capture such as $1, ${1},
$name, or ${name}Example vulnerable pattern:
location ~ ^/api/(.*)$ {
rewrite ^/api/(.*)$ /internal?migrated=true;
set $original_endpoint $1;
}
The scanner reports the location line, not the rewrite or set line,
because the location is the actionable block to inspect and fix.
The tests/fixtures/ directory contains small NGINX configs that can be used
as examples:
| Fixture | Expected result |
|---|---|
tests/fixtures/vulnerable.conf | reports a positional capture finding |
tests/fixtures/named_capture.conf | reports a named capture finding |
tests/fixtures/missing_include_still_scans.conf | reports a finding even though an include is missing |
tests/fixtures/safe_break_flag.conf | no finding because the rewrite uses break |
tests/fixtures/safe_no_capture.conf | no finding because no capture is available |
Run the scanner against all example fixtures:
uv run ./scan.py -r tests/fixtures
Expected findings:
/absolute/path/to/tests/fixtures/missing_include_still_scans.conf:6 -> location ~ ^/partial/(.*)$
/absolute/path/to/tests/fixtures/named_capture.conf:2 -> location /users
/absolute/path/to/tests/fixtures/vulnerable.conf:2 -> location ~ ^/api/(.*)$
If affected locations are found, each finding is printed on its own line:
/absolute/path/to/file.conf:30 -> location ~ ^/aaaa/dddd/(.*)$
/absolute/path/to/nginx.conf:39 -> location ~ ^/api/(.*)$
No output means no affected location was found in the parsed configuration.
This is a static configuration scanner. It does not:
Treat findings as locations that need review and remediation. A host is only actually affected when both the vulnerable NGINX version range and the risky configuration pattern are present.
Run the test suite:
uv run python -m unittest discover -s tests -v
Run the Go test suite:
cd go
go test ./...
Run the syntax check:
uv run python -m py_compile scan.py
Run against the bundled POC config:
uv run ./scan.py CVE-2026-42945-POC/env/nginx.conf
Expected output:
/absolute/path/to/CVE-2026-42945-POC/env/nginx.conf:39 -> location ~ ^/api/(.*)$