The Exploit
Requires only network access to a DAV-enabled aliased prefix location; no privileged credentials are needed if the MOVE/COPY endpoint is exposed.
curl -i -s -X MOVE 'http://TARGET/webdav/secret.txt' \
-H 'Host: TARGET' \
-H 'Destination: http://TARGET/' \
-H 'Content-Length: 0'
An affected NGINX worker typically returns 500 Internal Server Error or drops the connection, and the request can terminate the worker process as the malformed Destination header is processed. In practice, repeated requests against the aliased DAV location may show a worker restart or unexpected destination-file handling outside the document root.
What the Patch Did
Before:
depth = ngx_http_dav_depth(r, NGX_HTTP_DAV_INFINITY_DEPTH);
After:
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
if (clcf->alias
&& clcf->alias != NGX_MAX_SIZE_T_VALUE
&& duri.len < clcf->alias)
{
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"client sent invalid \"Destination\" header: \"%V\"",
&dest->value);
return NGX_HTTP_BAD_REQUEST;
}
depth = ngx_http_dav_depth(r, NGX_HTTP_DAV_INFINITY_DEPTH);
The patch adds an explicit validation step for the Destination header: it checks that the parsed destination URI length is not shorter than the configured alias length for the current location, and rejects malformed requests with NGX_HTTP_BAD_REQUEST.
Root Cause
This is improper input validation (CWE-20) leading to an out-of-bounds path handling bug. The attacker controls the Destination request header on a DAV MOVE/COPY request. In an aliased prefix location, NGINX later treats the destination URI as if it contains at least the alias prefix, but it never checked that duri.len was large enough. When duri.len < clcf->alias, the code continues and can operate on a destination path derived from a malformed header, crossing the trust boundary between client-supplied URI data and internal alias path handling.
Why It Works
The load-bearing check is the comparison duri.len < clcf->alias. Without that exact condition, the handler still accepts a Destination header whose path is shorter than the alias prefix, leaving the bad case live. The ngx_http_get_module_loc_conf() call is required to obtain the current alias length, while the return NGX_HTTP_BAD_REQUEST and logging are enforcement and diagnostic steps. The extra clcf->alias != NGX_MAX_SIZE_T_VALUE guard protects against special alias values, but the real bugfix is rejecting under-length destination URIs.
Hardening Checklist
- Enforce header-specific bounds before path computation: reject malformed
Destinationvalues with a400 Bad Request. - Use path normalization (
realpath()-style checks) before concatenating client-supplied paths with configured aliases. - Compare destination URI length against configured alias length before any alias-based file-system mapping.
- Prefer early-return defensive checks in request handlers instead of relying on later filesystem logic to catch invalid input.
References
- https://nvd.nist.gov/vuln/detail/CVE-2026-27654