CVE-2026-95101: How HTTP/3 Request Smuggling Slipped Past client_max_body_size
NGINX 1.30.6 and 1.31.7 close a parser bug that turned one variable into two jobs. CVE-2026-95101 lets an HTTP/3 client inject extra bytes into a proxied request, or deliver a body larger than client_max_body_size allows, by exploiting how unknown QUIC frames are skipped.
The mechanism
The HTTP/3 parser in NGINX tracks the remaining length of an unknown frame it is skipping. It also tracks how many DATA bytes to pass to the backend as request body. One field was used for both.
When an unknown frame arrived split across two reads, the leftover skip count from the first read was not cleared before the second read interpreted the field as a body count. The parser then treated the remainder of an unknown frame as DATA and forwarded it to the upstream. Because the bytes never passed through the body-size accounting, client_max_body_size never saw them.
F5 scores the flaw 6.9, the lowest of the five in this release, and credits Hansol Lee of GOTROOT.
Exploitation conditions
Two conditions must both hold. The server must terminate HTTP/3, which in NGINX means a listen directive carrying quic. And proxy_request_buffering must be left at its default of on, which is what causes NGINX to buffer and forward the request body rather than stream it through unchanged.
The affected range is 1.25.0 through 1.31.6, which tracks the maturity of the HTTP/3 implementation rather than the older TLS and rewrite code paths.
Why this is a smuggling class bug
The consequence is that the request the backend receives is not the request the client sent, as measured by NGINX's own accounting. Extra bytes appended to a proxied request are the definition of request smuggling, and smuggling desynchronises the front end from the back end.
A backend that applies its own limits, or that parses the body differently from NGINX, will act on a request NGINX never validated. On a typical deployment where NGINX fronts an application server, that is enough to reach endpoints the operator believed were protected by the front-end size limit.
The 6.9 score reflects the narrower precondition set: HTTP/3 is not ubiquitous, and a deployment without a QUIC listener is untouched. Where HTTP/3 is enabled, the flaw is a genuine front-end bypass rather than a simple denial of service.
Affected products and scope
NGINX open source from 1.25.0 through 1.31.6 is affected when HTTP/3 is enabled. F5's product advisories cover NGINX Plus and related F5 products separately, and several of those listed no fixed build as of 15 October, so Plus customers should read the F5 advisory rather than assume the open-source release date applies to them.
Remediation
Upgrade to 1.30.6 or 1.31.7.
Where an upgrade has to wait, F5's workaround is proxy_request_buffering off. With buffering disabled, NGINX streams the body instead of building a buffered copy from the miscounted DATA bytes, which removes the path that carried the injected content. The tradeoff is real: streaming changes how the upstream sees slow clients, so a team should test the change against its timeouts before rolling it out.
Disabling HTTP/3 entirely also removes the exposure, at the cost of losing QUIC benefits. For internal services where HTTP/3 was enabled speculatively, turning it off until the upgrade lands is the simplest decision.
Checking a server
Run nginx -T and search for listen lines containing quic. For each, check the value of proxy_request_buffering on the locations that proxy to a backend. A QUIC listener with default buffering is the exposed combination.
This is one of the few flaws in the October release where the condition is partly on by default, which means version alone is a stronger signal here than for the memory-safety bugs: an affected version with HTTP/3 enabled and default buffering is exposed, regardless of what other directives the configuration uses.
Sources
- NGINX security advisories: https://nginx.org/en/security_advisories.html
- F5 advisory K000162613: https://my.f5.com/manage/s/article/K000162613
- HTTP/3 parser fix commit: https://github.com/nginx/nginx/commit/1c173a2d8767730e678c27446138d7ae5dd6fd64
- proxy_request_buffering documentation: https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_request_buffering
- NGINX download page: https://nginx.org/en/download.html
Top comments (0)