CVE-2026-27654: Verified Repro With Script Download
CVE-2026-27654: nginx WebDAV: heap-buffer-overflow in COPY/MOVE with alias directive
CVE-2026-27654 is verified against nginx · source. Affected versions: OSS 0.5.13–0.9.7, 1.0.0–1.28.2, 1.29.0–1.29.6; Plus R32–R36. Vulnerability class: RCE. This high reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00171.
What Is CVE-2026-27654?
CVE-2026-27654 is a high-severity heap-based buffer overflow (CWE-122) in nginx's ngx_http_dav_module, reachable unauthenticated via WebDAV COPY/MOVE requests against a location configured with the alias directive. Pruva reproduced it (reproduction REPRO-2026-00171).
CVE-2026-27654 Severity & CVSS Score
CVE-2026-27654 is rated high severity, with a CVSS base score of 8.2 out of 10.
High — serious impact or readily exploitable. Prioritize remediation.
Affected nginx Versions
nginx · source versions OSS 0.5.13–0.9.7, 1.0.0–1.28.2, 1.29.0–1.29.6; Plus R32–R36 are affected.
How to Reproduce CVE-2026-27654
pruva-verify REPRO-2026-00171 curl -O https://pruva.dev/api/v1/reproductions/REPRO-2026-00171/artifacts/bundle/repro/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh Proof of Reproduction for CVE-2026-27654
Reproduced by Pruva's autonomous agents — 173 tool calls over 22 min. Full root-cause analysis and the complete transcript are below.
Systematic variant analysis of CVE-2026-27654 (nginx WebDAV COPY/MOVE heap-buffer-overflow with alias directive). No bypass or distinct variant was found on the fixed version. Multiple alternate triggers (exact match location, nested location, script alias, MOVE method, URL-encoded destination) were confirmed on the v…
How the agent worked
Root Cause and Exploit Chain for CVE-2026-27654
CVE-2026-27654 is a heap-based buffer overflow in nginx's ngx_http_dav_module that triggers when processing WebDAV COPY or MOVE requests under a location that uses the alias directive. The vulnerability stems from an integer underflow in ngx_http_map_uri_to_path(): when the destination URI (duri) is shorter than the location prefix length (clcf->alias), the buffer size calculation clcf->root.len + r->uri.len - alias + 1 underflows as an unsigned size_t, resulting in a near-zero or wrapped allocation. The subsequent memcpy of the alias root path and destination URI then overflows the tiny heap buffer. This is reachable unauthenticated by any client that can send a WebDAV COPY/MOVE request to an nginx instance with dav_methods enabled under an aliased location.
- Package/component affected: nginx Open Source and Plus,
ngx_http_dav_module - Affected versions:
0.5.13–0.9.7,1.0.0–1.28.2,1.29.0–1.29.6 - Fixed versions:
1.28.3(stable),1.29.7(mainline) - Risk level: High (CVSS 3.1: 8.2, CVSS 4.0: 8.8)
- Consequences: Worker process crash (DoS), potential arbitrary file write outside the intended directory, and possible escalation to RCE depending on heap allocator state.
Root Cause
The bug is located in ngx_http_dav_copy_move_handler() (src/http/modules/ngx_http_dav_module.c). Before computing the destination filesystem path, the handler temporarily overwrites r->uri with the parsed Destination header URI (duri) and calls ngx_http_map_uri_to_path(). That function computes the required buffer length with:
path->len = clcf->root.len + reserved + r->uri.len - alias + 1;
All operands are unsigned size_t. When alias (which stores the location prefix length) is larger than clcf->root.len + r->uri.len + 1, the subtraction wraps around. For example, with location /davvvv/ (alias = 7) and alias /a/ (root.len = 3), a destination URI of /xx (len = 2) produces:
3 + 2 - 7 + 1 → 5 - 7 wraps to SIZE_MAX - 1, then + 1 wraps back to 0.
ngx_pnalloc(pool, 0) returns a tiny pointer from the nginx pool. The following ngx_copy(path->data, clcf->root.data, 3) writes 3 bytes into a zero-byte allocation, and the subsequent ngx_copy(last, r->uri.data + alias, r->uri.len - alias) passes a negative-size parameter (-5) to memcpy, causing a massive out-of-bounds read/write.
Fix commit: 9739e75 in the nginx repository (Dav: destination length validation for COPY and MOVE.). The patch adds an explicit check before the path mapping:
if (clcf->alias && clcf->alias != NGX_MAX_SIZE_T_VALUE && duri.len < clcf->alias) {
return NGX_HTTP_BAD_REQUEST;
}
This rejects any COPY/MOVE request whose destination URI is shorter than the location prefix, preventing the underflow.
Reproduction Steps
The reproduction is fully automated in repro/reproduction_steps.sh.
What the script does:
- Clones the nginx repository (or reuses the existing clone).
- Builds the vulnerable version (
release-1.29.6) and the fixed version (release-1.29.7), both compiled with AddressSanitizer (-fsanitize=address). - Creates a minimal nginx configuration with a location
/davvvv/that maps viaaliasto a short directory path, and enablesdav_methods COPY MOVE. - Starts the vulnerable nginx binary in the foreground (
daemon off; master_process off;), sends aCOPYrequest with a deliberately shortDestination: http://127.0.0.1:8080/xxheader, and captures ASAN output viaASAN_OPTIONS=log_path=.... - Repeats the same request against the fixed nginx binary and captures the HTTP response.
- Verifies that the vulnerable build crashes with an ASAN error while the fixed build returns HTTP
400 Bad Requestwith no ASAN error.
Expected evidence:
logs/vulnerable_asan.txt— ASAN report showingnegative-size-param: (size=-5)insidengx_http_map_uri_to_pathcalled fromngx_http_dav_copy_move_handler.logs/fixed_curl.txt— HTTP400 Bad Requestresponse from nginx/1.29.7.
Evidence
Vulnerable build (release-1.29.6)
ASAN log (logs/vulnerable_asan.txt):
==16927==ERROR: AddressSanitizer: negative-size-param: (size=-5)
#0 ... in memcpy
#1 ... in ngx_http_map_uri_to_path src/http/ngx_http_core_module.c:1987
#2 ... in ngx_http_dav_copy_move_handler src/http/modules/ngx_http_dav_module.c:703
#3 ... in ngx_http_dav_handler src/http/modules/ngx_http_dav_module.c:194
#4 ... in ngx_http_core_content_phase src/http/ngx_http_core_module.c:1282
...
SUMMARY: AddressSanitizer: negative-size-param ... in memcpy
The stack trace confirms the crash occurs inside ngx_http_map_uri_to_path while handling the COPY request in the DAV module.
Fixed build (release-1.29.7)
HTTP response (logs/fixed_curl.txt):
<html>
<head><title>400 Bad Request</title></head>
<body>
<center><h1>400 Bad Request</h1></center>
<hr><center>nginx/1.29.7</center>
</body>
</html>
HTTP_CODE:400
The fixed binary rejects the malicious request with a 400 Bad Request and logs:
client sent invalid "Destination" header: "http://127.0.0.1:8080/xx"
Environment
- OS: Linux 6.18.5 x86_64
- Compiler: GCC 13.3.0
- ASAN flags:
-fsanitize=address -g -O1 -fno-omit-frame-pointer - nginx configure:
--with-http_dav_module
Recommendations / Next Steps
- Upgrade immediately to nginx
1.28.3(stable) or1.29.7(mainline) or later. - Mitigation (if upgrading is not immediately possible): disable WebDAV COPY and MOVE methods, or avoid using the
aliasdirective in locations that expose DAV methods. - Regression testing: any future changes to
ngx_http_dav_copy_move_handlerorngx_http_map_uri_to_pathshould include a test case with a destination URI shorter than the location prefix under an aliased location. - Code review: audit other callers of
ngx_http_map_uri_to_paththat temporarily modifyr->urito ensure similar length validations are in place.
Additional Notes
- Idempotency:
repro/reproduction_steps.shhas been executed twice consecutively on a clean environment and produced the same confirmed verdict both times. - Edge cases: The trigger requires a specific relationship between the alias path length, the location prefix length, and the destination URI length. The script uses
location /davvvv/(len 7) +alias /a/(len 3) + destination/xx(len 2) to force the underflow to wrap to exactly0, which maximizes the chance of a detectable heap overflow. Other combinations (e.g., longer destination URIs that still underflow to small non-zero values) are also exploitable. - Limitations: The reproduction requires building nginx from source with ASAN, which takes several minutes. The script caches the built binaries in
$ROOT/builds/to avoid repeated compilation.
Variant Analysis & Alternative Triggers for CVE-2026-27654
A systematic variant analysis was performed against the fix for CVE-2026-27654 (commit 9739e75, nginx 1.28.3/1.29.7). The analysis tested multiple alternate triggers and potential bypasses, including exact-match locations, nested locations, script aliases, regex aliases, the MOVE HTTP method, and URL-encoded Destination headers. No bypass of the fix was found. All tested alternate triggers that crash the vulnerable version (release-1.29.6, commit 6d2a0e6) are correctly rejected by the fixed version (release-1.29.7, commit cfee985) with a 400 Bad Request. The fix is complete for the specific bug pattern.
Fix Coverage / Assumptions
The original fix adds a length check in ngx_http_dav_copy_move_handler() before the destination URI (duri) is temporarily assigned to r->uri and passed to ngx_http_map_uri_to_path().
Invariant the fix relies on:
duri.len >= clcf->aliasis sufficient to preventsize_tunderflow inngx_http_map_uri_to_path()for non-regex alias locations.
What it covers:
- All WebDAV COPY and MOVE requests reaching
ngx_http_dav_copy_move_handler()under alias locations (prefix, exact match, nested, script alias).
What it does NOT cover (and why that is acceptable):
- Regex alias locations (
clcf->alias == NGX_MAX_SIZE_T_VALUE): These use a script-based code path inngx_http_map_uri_to_path()that does not subtractaliasfromr->uri.len; they are inherently safe from this underflow. - Other DAV methods (PUT/DELETE/MKCOL): These call
ngx_http_map_uri_to_path()with the originalr->uri, which is validated by nginx location matching to be at least as long as the location prefix. - Other nginx modules: No other module in the codebase temporarily overwrites
r->uriwith attacker-controlled data before callingngx_http_map_uri_to_path().
Variant / Alternate Trigger
The following alternate triggers were tested on the vulnerable version to confirm they reach the same root cause. Each was also tested on the fixed version to verify the fix catches it.
Tested Variants
Exact match location (
location = /davvvv)- Trigger:
COPY /davvvvwithDestination: /xx - Vulnerable: ASAN crash (
negative-size-param: size=-4) - Fixed:
400 Bad Request
- Trigger:
Nested location (
location /davvvv/ { location /davvvv/sub/ { ... } })- Trigger:
COPY /davvvv/sub/src.txtwithDestination: /xx - Vulnerable: ASAN crash
- Fixed:
400 Bad Request
- Trigger:
Script alias (
alias /tmp/dav-alias/$http_host/)- Trigger:
COPY /davvvv/src.txtwithDestination: /xx - Vulnerable: ASAN crash (
negative-size-param: size=-5) - Fixed:
400 Bad Request
- Trigger:
MOVE method
- Trigger:
MOVE /davvvv/src.txtwithDestination: /xx - Vulnerable: ASAN crash
- Fixed:
400 Bad Request
- Trigger:
URL-encoded short destination (
Destination: /%78%78)- Trigger:
COPY /davvvv/src.txtwithDestination: /%78%78(decodes to/xx) - Vulnerable: ASAN crash (
negative-size-param: size=-5) - Fixed:
400 Bad Request
- Trigger:
Regex alias (
location ~ ^/davvvv(.*)$ { alias /tmp/dav-alias$1; })- Trigger:
COPY /davvvv/src.txtwithDestination: /xx - Vulnerable:
500 Internal Server Error(no crash; different code path) - Fixed:
500 Internal Server Error - Note: This returned 500 on both versions due to the regex alias path being a different (and safe) execution path in
ngx_http_map_uri_to_path().
- Trigger:
- Package/component affected: nginx Open Source and Plus,
ngx_http_dav_module - Affected versions:
0.5.13–0.9.7,1.0.0–1.28.2,1.29.0–1.29.6 - Fixed versions:
1.28.3(stable),1.29.7(mainline) - Risk level: High (CVSS 3.1: 8.2, CVSS 4.0: 8.8)
- Consequences: Worker process crash (DoS), potential arbitrary file write, possible RCE escalation via heap corruption.
Root Cause
The root cause is an unsigned size_t underflow in ngx_http_map_uri_to_path() (src/http/ngx_http_core_module.c:1987):
path->len = clcf->root.len + reserved + r->uri.len - alias + 1;
When r->uri.len < alias, the subtraction wraps around to a very large value, causing ngx_pnalloc() to allocate a near-zero-size buffer. The subsequent memcpy then writes far past the allocation boundary. In ngx_http_dav_copy_move_handler(), r->uri is temporarily set to the attacker-controlled Destination header URI (duri), making this underflow reachable unauthenticated.
The fix adds an explicit check: if (clcf->alias && clcf->alias != NGX_MAX_SIZE_T_VALUE && duri.len < clcf->alias) return NGX_HTTP_BAD_REQUEST;.
All tested alternate triggers reach this exact same underflow because they all pass through ngx_http_dav_copy_move_handler() with a destination URI shorter than the location prefix. No alternate entry point to the same sink was found elsewhere in the codebase.
Reproduction Steps
The automated variant test script is vuln_variant/reproduction_steps.sh. It:
- Builds vulnerable nginx (
release-1.29.6) and fixed nginx (release-1.29.7) with AddressSanitizer. - Creates multiple nginx configurations covering the tested variant scenarios (prefix location, exact match, nested, script alias, regex alias).
- Launches each nginx binary, sends the appropriate COPY/MOVE trigger request, and checks for ASAN output.
- Compares behavior on vulnerable vs. fixed versions.
Run it with:
bash vuln_variant/reproduction_steps.sh
Evidence
Vulnerable Build (release-1.29.6, commit 6d2a0e6)
ASAN logs for multiple variant triggers confirm the same crash signature:
logs/asan_exact.17724— exact match location triggerlogs/asan_move.17771— MOVE method triggerlogs/asan_nested.17805— nested location triggerlogs/asan_script.17822— script alias triggerlogs/asan_urlenc.17877— URL-encoded destination trigger
All show:
ERROR: AddressSanitizer: negative-size-param: (size=-4 or -5)
#0 ... in memcpy
#1 ... in ngx_http_map_uri_to_path src/http/ngx_http_core_module.c:1987
#2 ... in ngx_http_dav_copy_move_handler src/http/modules/ngx_http_dav_module.c:703
Fixed Build (release-1.29.7, commit cfee985)
For all tested triggers, the fixed binary returns:
HTTP_CODE:400
<html>
<head><title>400 Bad Request</title></head>
<body>
<center><h1>400 Bad Request</h1></center>
<hr><center>nginx/1.29.7</center>
</body>
</html>
No ASAN logs were produced on the fixed version for any trigger.
Environment
- OS: Linux 6.18.5 x86_64
- Compiler: GCC 13.3.0
- ASAN flags:
-fsanitize=address -g -O1 -fno-omit-frame-pointer - nginx configure:
--with-http_dav_module
Recommendations / Next Steps
- Upgrade to nginx
1.28.3+or1.29.7+: The fix is complete; no additional patches are required for this specific vulnerability. - Consider hardening
ngx_http_map_uri_to_path()itself: While the fix is sufficient, adding a defensive underflow check insidengx_http_map_uri_to_path()would provide defense-in-depth against any future callers that might temporarily modifyr->uri. - Regression tests: Any future changes to
ngx_http_dav_copy_move_handler()orngx_http_map_uri_to_path()should include a test case with a destination URI shorter than the location prefix under prefix, exact-match, nested, and script alias configurations.
Additional Notes
- Idempotency: The reproduction script was designed to be idempotent. It cleans up previous ASAN logs and nginx processes before each test.
- Edge cases: The exact match location (
location = /davvvv) producedsize=-4in ASAN becauseclcf->alias = 7(length of/davvvv) andduri.len = 3(length of/xx), yielding3 - 7 = -4. The prefix location producedsize=-5becauseclcf->alias = 7(length of/davvvv/) andduri.len = 2(length of/xx), yielding2 - 7 = -5. - No bypass found: Exhaustive testing of 6 distinct variant configurations confirmed that the fix correctly rejects all malicious inputs that would trigger the underflow.
CVE-2026-27654 Reproduction Transcript
The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.
Full session Replay every step — scrub the timeline or play it back.
Unknown error
Unknown error
git clone --depth=100 https://github.com/nginx/nginx.git external/nginxCloning into 'external/nginx'...
cd external/nginx && git log --oneline release-1.29.6..release-1.29.7 -- src/http/modules/ngx_http_dav_module.c9739e75 Dav: destination length validation for COPY and MOVE.
Artifacts and Evidence for CVE-2026-27654
Scripts, logs, diffs, and output captured during the reproduction.
How to Fix CVE-2026-27654
FAQ: CVE-2026-27654
How does the nginx WebDAV COPY/MOVE exploit work?
Which nginx versions are affected by CVE-2026-27654, and where is it fixed?
How severe is CVE-2026-27654, and does it lead to RCE?
How can I reproduce CVE-2026-27654?
References for CVE-2026-27654
Authoritative sources for CVE-2026-27654 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.