{"repro_id":"REPRO-2026-00308","version":6,"title":"NGINX ASLR-enabled network RCE","repro_type":"security","status":"published","severity":"critical","description":"Demonstrate genuine remote command execution for CVE-2026-42533 against NGINX commit `28219209e0b4f9e155fd8bd91ab81b8ac30628f2` while ASLR remains enabled. The attacker must be a separate network peer and may only use the target's real HTTP/TCP listeners. The proof must create a target-local command marker that is subsequently observable through the application boundary.","root_cause":"## Summary\n\nCVE-2026-42533 is a memory-safety flaw in NGINX complex script/value evaluation for HTTP variables. A crafted configuration using regular-expression captures, a volatile map, slice/proxy processing, and a second overflow path can make the length pass and value-copy pass observe different capture contents. In the vulnerable commit, NGINX allocates based on the stale/short length and then copies attacker-controlled bytes from a later capture state, enabling a heap overwrite through real HTTP/TCP requests. The current run confirmed the full claimed impact: ASLR-enabled remote command execution from a separate network peer against NGINX commit `28219209e0b4f9e155fd8bd91ab81b8ac30628f2`, with fixed commit `b767540492e8c79a58bc26034d3bab2f708b7bd1` failing closed as a negative control.\n\n## Impact\n\n- Package/component affected: NGINX Open Source, HTTP script/variable processing (`src/http/ngx_http_script.c`, related capture handling), exercised through the HTTP map, regex location, slice, and proxy modules.\n- Affected versions: the vulnerable source commit validated by this run is `28219209e0b4f9e155fd8bd91ab81b8ac30628f2`; the fixed negative-control commit is `b767540492e8c79a58bc26034d3bab2f708b7bd1`.\n- Risk level and consequences: critical. A remote peer able to send crafted HTTP requests to the configured NGINX listener can turn the capture length/value mismatch into target-worker command execution when the vulnerable configuration preconditions are present. The proof command writes a harmless target-local marker and retrieves it via HTTP.\n\n## Impact Parity\n\n- Disclosed/claimed maximum impact: `code_execution` through the NGINX HTTP/TCP listener while ASLR remains enabled.\n- Reproduced impact from this run: `code_execution`. The final successful run created two run-unique target-local command markers in two fresh vulnerable NGINX workers and retrieved them through `/rce-proof`; the same attacker procedure against the fixed commit did not create markers.\n- Parity: `full`.\n- Not demonstrated: no stronger impact than command execution is claimed. Sanitizers, debugger-derived addresses, and disabled ASLR were not used by the primary proof.\n\n## Root Cause\n\nThe vulnerable path is a time-of-check/time-of-use mismatch inside NGINX script complex-value evaluation. During the length calculation pass, a variable/capture can have one size, but during the value-copy pass a volatile map and regex capture sequence can change the capture contents. The vulnerable code trusts the previously calculated size and does not check that later copied script-variable bytes still fit into the allocated destination buffer. The fixed commit `b767540492e8c79a58bc26034d3bab2f708b7bd1` adds `ngx_http_script_check_length` and corresponding checks so a later value that exceeds the computed allocation is rejected instead of being copied past the destination.\n\nFix commit: https://github.com/nginx/nginx/commit/b767540492e8c79a58bc26034d3bab2f708b7bd1\n\n## Reproduction Steps\n\n1. Run `bundle/repro/reproduction_steps.sh` from any directory. The script uses `PRUVA_ROOT` when set and otherwise resolves the bundle root relative to itself.\n2. The script reads `bundle/project_cache_context.json`, reuses `/pruva/project-cache/repo` when the prepared cache is available, resolves and archives the exact vulnerable and fixed commits, verifies that the vulnerable source lacks `ngx_http_script_check_length` and the fixed source contains it, and builds hardened Docker images for each tree.\n3. It generates the calibrated NGINX configuration and Python support programs at runtime, starts real NGINX target containers with ASLR enabled, and launches separate attacker containers on a Docker network. The attacker obtains same-worker disclosure data only through the NGINX HTTP listener, performs heap shaping and the overflow through HTTP/TCP, and retrieves `/rce-proof` through the NGINX listener.\n4. Expected evidence of reproduction is two vulnerable trial logs containing `EXPLOIT_CONFIRMED marker=...`, marker files whose contents match the run-unique marker, two fixed negative-control observations with `marker_present=false`, and verifier evidence showing different randomized mappings between vulnerable trials.\n\n## Evidence\n\nPrimary evidence locations written by the script:\n\n- `bundle/logs/reproduction_steps.log` — full build and runtime transcript.\n- `bundle/logs/randomize_va_space.log` — kernel ASLR setting (`2` in the final successful run).\n- `bundle/logs/patch_hunk_verification.log` — vulnerable/fixed patch-hunk verification.\n- `bundle/logs/vulnerable-1.attacker.log` and `bundle/logs/vulnerable-2.attacker.log` — separate network peer exploit transcripts.\n- `bundle/logs/vulnerable-1.marker` and `bundle/logs/vulnerable-2.marker` — marker bodies retrieved through `/rce-proof`.\n- `bundle/logs/vulnerable-1.maps` and `bundle/logs/vulnerable-2.maps` — verifier process maps captured after service start and not used as exploit inputs.\n- `bundle/logs/vulnerable-1.mitigations` and `bundle/logs/vulnerable-2.mitigations` — readelf/ldd/file hardening and loader evidence.\n- `bundle/logs/fixed-1.attacker.log`, `bundle/logs/fixed-2.attacker.log`, and fixed observation JSON files — fixed negative-control evidence.\n- `bundle/logs/proof_summary.json` — structured summary combining vulnerable and fixed observations.\n- `bundle/repro/runtime_manifest.json` — runtime-backed manifest for the TCP peer entrypoint.\n\nKey excerpts from the final successful run:\n\n- `VULNERABLE_ATTEMPT_CONFIRMED role=vulnerable attempt=1 marker=PRUVA_42533_VULNERABLE_1_1784957428_6AA723FB`\n- `VULNERABLE_ATTEMPT_CONFIRMED role=vulnerable attempt=2 marker=PRUVA_42533_VULNERABLE_2_1784957430_DAEE2FFD`\n- `FIXED_NEGATIVE_CONTROL_OK role=fixed attempt=1 attacker_rc=1 marker_present=false marker=PRUVA_42533_FIXED_1_1784957432_FBE549D5`\n- `FIXED_NEGATIVE_CONTROL_OK role=fixed attempt=2 attacker_rc=1 marker_present=false marker=PRUVA_42533_FIXED_2_1784957441_7727967F`\n- `ASLR verifier: vulnerable executable mapping bases differ: 0x55d551e45000 vs 0x564f17702000`\n\n`bundle/logs/proof_summary.json` records `confirmed=true`, vulnerable build ID `b9bb7df3e0b9ec8f3ea74448be3d11ca926eef45`, vulnerable executable SHA-256 `4b01896ce3283476723310e42a8f39f78d45c560309f546b90d7bd9e87a3d4a7`, fixed build ID `2b428651367e71c91898b797fb532cb5a18ac8e2`, and fixed executable SHA-256 `16e242c2965b52ce9dfce13158d7812845e700e15d968c9f35dc2bf568fffdf1`.\n\n## Recommendations / Next Steps\n\n- Upgrade to a release or commit containing `b767540492e8c79a58bc26034d3bab2f708b7bd1` or equivalent script length validation.\n- Keep HTTP variable/capture regression tests that force length-pass and copy-pass capture divergence, including volatile map, regex location, proxy, and slice module combinations.\n- Treat configurations that combine attacker-controlled regex captures with complex variable expansion as high-risk until patched.\n- Maintain hardening such as PIE, NX, RELRO, stack canaries, and ASLR, but do not rely on those mitigations as a substitute for the length check.\n\n## Additional Notes\n\nThe reproduction is idempotent: it creates fresh Docker containers and a fresh Docker network per run, removes them on exit, rebuilds or verifies exact source commits, and writes fresh current-run evidence under `bundle/logs/` and `bundle/repro/`. The final script version was executed successfully after all edits. Historical exploit-knowledge records were used only as reference mechanics; all verdict-relevant evidence comes from current script executions.","cve_id":"CVE-2026-42533","source_url":"https://github.com/nginx/nginx","package":{"name":"nginx/nginx","ecosystem":"github","affected_versions":"NGINX security index lists Open Source 0.9.6-1.31.2 as vulnerable and 1.31.3+ or 1.30.4+ as not vulnerable. F5 also lists NGINX Plus 37.0.0.1-37.0.2.1 fixed in 37.0.3.1 and R33-R36 fixed in R36 P7."},"reproduced_at":"2026-07-27T20:38:43.672765+00:00","duration_secs":4304.0,"tool_calls":368,"handoffs":1,"total_cost_usd":28.169962,"agent_costs":{"claim_matcher":0.054194,"judge":1.024813,"learning_policy":0.002231,"repro":21.57468,"support":0.44568,"vuln_variant":5.068364},"cost_breakdown":{"claim_matcher":{"gpt-5.5-2026-04-23":0.054194},"judge":{"gpt-5.5":1.024813},"learning_policy":{"gpt-5.4-mini-2026-03-17":0.002231},"repro":{"gpt-5.5":21.57468},"support":{"gpt-5.5":0.44568},"vuln_variant":{"gpt-5.5":5.068364}},"quality":{"confidence":"high","idempotent_verified":false,"community_verifications":0},"evidence":{"workflow":{"profile":"known_vulnerability","schema_version":2,"stages":["support","claim_contract","repro","judge","vuln_variant"]}},"environment":{"sandbox_image":"ghcr.io/n3mes1s/pruva-sandbox@sha256:8096b2518d6022e13d68f885c3b8ded6b4fe607098b1a1ccbfb99abc004d1dc1"},"published_at":"2026-07-27T20:38:44.935167+00:00","retracted":false,"artifacts":[{"path":"bundle/repro/reproduction_steps.sh","filename":"reproduction_steps.sh","size":34606,"category":"reproduction_script"},{"path":"bundle/repro/rca_report.md","filename":"rca_report.md","size":7571,"category":"analysis"},{"path":"bundle/logs/fixed-1.randomization-base","filename":"fixed-1.randomization-base","size":15,"category":"other"},{"path":"bundle/logs/fixed-2.leak-backend.log","filename":"fixed-2.leak-backend.log","size":0,"category":"log"},{"path":"bundle/logs/fixed-2.exploit-backend.log","filename":"fixed-2.exploit-backend.log","size":1200,"category":"log"},{"path":"bundle/repro/validation_verdict.json","filename":"validation_verdict.json","size":1043,"category":"other"},{"path":"bundle/repro/runtime_manifest.json","filename":"runtime_manifest.json","size":3313,"category":"other"},{"path":"bundle/logs/reproduction_steps.log","filename":"reproduction_steps.log","size":2247,"category":"log"},{"path":"bundle/logs/fixed-1.attacker.log","filename":"fixed-1.attacker.log","size":6442,"category":"log"},{"path":"bundle/logs/fixed-2.attacker.log","filename":"fixed-2.attacker.log","size":6442,"category":"log"},{"path":"bundle/logs/fixed-2.mitigations","filename":"fixed-2.mitigations","size":101877,"category":"other"},{"path":"bundle/logs/aslr_verifier.log","filename":"aslr_verifier.log","size":92,"category":"log"},{"path":"bundle/logs/patch_hunk_verification.log","filename":"patch_hunk_verification.log","size":100,"category":"log"},{"path":"bundle/logs/fixed_commit_stat.log","filename":"fixed_commit_stat.log","size":312,"category":"log"},{"path":"bundle/logs/fixed_commit_detail.log","filename":"fixed_commit_detail.log","size":2139,"category":"log"},{"path":"bundle/logs/nginx_conf_sha256.log","filename":"nginx_conf_sha256.log","size":83,"category":"log"},{"path":"bundle/logs/vulnerable-docker-build.log","filename":"vulnerable-docker-build.log","size":1690,"category":"log"},{"path":"bundle/logs/fixed-docker-build.log","filename":"fixed-docker-build.log","size":1685,"category":"log"},{"path":"bundle/logs/vulnerable-1.healthcheck.log","filename":"vulnerable-1.healthcheck.log","size":174,"category":"log"},{"path":"bundle/logs/vulnerable-1.target.inspect.json","filename":"vulnerable-1.target.inspect.json","size":9099,"category":"other"},{"path":"bundle/logs/vulnerable-1.worker-pid","filename":"vulnerable-1.worker-pid","size":3,"category":"other"},{"path":"bundle/logs/vulnerable-1.build-id","filename":"vulnerable-1.build-id","size":41,"category":"other"},{"path":"bundle/logs/vulnerable-1.binary-sha256","filename":"vulnerable-1.binary-sha256","size":65,"category":"other"},{"path":"bundle/logs/vulnerable-1.randomization-base","filename":"vulnerable-1.randomization-base","size":15,"category":"other"},{"path":"bundle/logs/vulnerable-1.attacker.inspect.json","filename":"vulnerable-1.attacker.inspect.json","size":8354,"category":"other"},{"path":"bundle/logs/vulnerable-1.proof-http-response","filename":"vulnerable-1.proof-http-response","size":276,"category":"other"},{"path":"bundle/logs/vulnerable-1.container.log","filename":"vulnerable-1.container.log","size":113,"category":"log"},{"path":"bundle/logs/vulnerable-1.nginx-error.log","filename":"vulnerable-1.nginx-error.log","size":720,"category":"log"},{"path":"bundle/logs/vulnerable-1.leak-backend.log","filename":"vulnerable-1.leak-backend.log","size":0,"category":"log"},{"path":"bundle/logs/vulnerable-1.exploit-backend.log","filename":"vulnerable-1.exploit-backend.log","size":1901,"category":"log"},{"path":"bundle/logs/vulnerable-2.healthcheck.log","filename":"vulnerable-2.healthcheck.log","size":174,"category":"log"},{"path":"bundle/logs/vulnerable-2.target.inspect.json","filename":"vulnerable-2.target.inspect.json","size":9100,"category":"other"},{"path":"bundle/logs/vulnerable-2.worker-pid","filename":"vulnerable-2.worker-pid","size":3,"category":"other"},{"path":"bundle/logs/vulnerable-2.build-id","filename":"vulnerable-2.build-id","size":41,"category":"other"},{"path":"bundle/logs/vulnerable-2.binary-sha256","filename":"vulnerable-2.binary-sha256","size":65,"category":"other"},{"path":"bundle/logs/vulnerable-2.randomization-base","filename":"vulnerable-2.randomization-base","size":15,"category":"other"},{"path":"bundle/logs/vulnerable-2.attacker.inspect.json","filename":"vulnerable-2.attacker.inspect.json","size":8354,"category":"other"},{"path":"bundle/logs/vulnerable-2.proof-http-response","filename":"vulnerable-2.proof-http-response","size":276,"category":"other"},{"path":"bundle/logs/vulnerable-2.container.log","filename":"vulnerable-2.container.log","size":113,"category":"log"},{"path":"bundle/logs/vulnerable-2.nginx-error.log","filename":"vulnerable-2.nginx-error.log","size":720,"category":"log"},{"path":"bundle/logs/vulnerable-2.leak-backend.log","filename":"vulnerable-2.leak-backend.log","size":0,"category":"log"},{"path":"bundle/logs/vulnerable-2.exploit-backend.log","filename":"vulnerable-2.exploit-backend.log","size":1901,"category":"log"},{"path":"bundle/logs/fixed-1.healthcheck.log","filename":"fixed-1.healthcheck.log","size":174,"category":"log"},{"path":"bundle/logs/fixed-1.target.inspect.json","filename":"fixed-1.target.inspect.json","size":9085,"category":"other"},{"path":"bundle/logs/fixed-1.worker-pid","filename":"fixed-1.worker-pid","size":3,"category":"other"},{"path":"bundle/logs/fixed-1.maps","filename":"fixed-1.maps","size":5799,"category":"other"},{"path":"bundle/logs/fixed-1.build-id","filename":"fixed-1.build-id","size":41,"category":"other"},{"path":"bundle/logs/fixed-1.binary-sha256","filename":"fixed-1.binary-sha256","size":65,"category":"other"},{"path":"bundle/logs/fixed-1.attacker.inspect.json","filename":"fixed-1.attacker.inspect.json","size":8329,"category":"other"},{"path":"bundle/logs/fixed-1.marker","filename":"fixed-1.marker","size":153,"category":"other"},{"path":"bundle/logs/fixed-1.proof-http-response","filename":"fixed-1.proof-http-response","size":303,"category":"other"},{"path":"bundle/logs/fixed-1.container.log","filename":"fixed-1.container.log","size":113,"category":"log"},{"path":"bundle/logs/fixed-1.nginx-error.log","filename":"fixed-1.nginx-error.log","size":7250,"category":"log"},{"path":"bundle/logs/fixed-1.leak-backend.log","filename":"fixed-1.leak-backend.log","size":0,"category":"log"},{"path":"bundle/logs/fixed-1.exploit-backend.log","filename":"fixed-1.exploit-backend.log","size":1200,"category":"log"},{"path":"bundle/logs/fixed-2.healthcheck.log","filename":"fixed-2.healthcheck.log","size":174,"category":"log"},{"path":"bundle/logs/fixed-2.target.inspect.json","filename":"fixed-2.target.inspect.json","size":9085,"category":"other"},{"path":"bundle/logs/fixed-2.worker-pid","filename":"fixed-2.worker-pid","size":3,"category":"other"},{"path":"bundle/logs/fixed-2.maps","filename":"fixed-2.maps","size":5799,"category":"other"},{"path":"bundle/logs/fixed-2.build-id","filename":"fixed-2.build-id","size":41,"category":"other"},{"path":"bundle/logs/fixed-2.binary-sha256","filename":"fixed-2.binary-sha256","size":65,"category":"other"},{"path":"bundle/logs/fixed-2.randomization-base","filename":"fixed-2.randomization-base","size":15,"category":"other"},{"path":"bundle/logs/fixed-2.attacker.inspect.json","filename":"fixed-2.attacker.inspect.json","size":8329,"category":"other"},{"path":"bundle/logs/fixed-2.marker","filename":"fixed-2.marker","size":153,"category":"other"},{"path":"bundle/logs/fixed-2.proof-http-response","filename":"fixed-2.proof-http-response","size":303,"category":"other"},{"path":"bundle/logs/fixed-2.container.log","filename":"fixed-2.container.log","size":113,"category":"log"},{"path":"bundle/logs/fixed-2.nginx-error.log","filename":"fixed-2.nginx-error.log","size":7250,"category":"log"}]}