Status: Patched
This vulnerability has been verified as resolved and deployed.
HTTP/2 upstream frame injection via oversized proxy_set_body (CVE-2026-42926)
Summary
NGINX serialized proxy_set_body output as one HTTP/2 DATA frame and truncated the 24-bit frame length
When proxy_http_version 2 selected the HTTP/2 upstream proxy path and proxy_set_body generated a custom request body, ngx_http_proxy_v2_create_request() appended that body directly after a single DATA frame header in the initial upstream buffer.
HTTP/2 frame lengths are 24-bit values. The vulnerable code stored body_len into length_0, length_1, and length_2 without checking or fragmenting bodies larger than 16,777,215 bytes. If proxy_set_body produced a body over that limit, the encoded DATA frame length wrapped to the low 24 bits while the full body bytes were still sent. The upstream HTTP/2 peer would consume only the wrapped length as DATA payload, then parse the remaining attacker-controlled body bytes as subsequent HTTP/2 frame headers and payload.
The F5 CNA record for CVE-2026-42926 describes this as an ngx_http_proxy_v2_module encoding error affecting NGINX Open Source configurations that set proxy_http_version to 2 and also use proxy_set_body. The upstream fix in commit c24fb25 stops inlining proxy_set_body output as a prebuilt DATA frame; it places the generated body in a normal request-body chain so ngx_http_proxy_v2_body_output_filter() frames it into bounded DATA frames respecting NGX_HTTP_V2_DEFAULT_FRAME_SIZE and flow-control windows.
CVSS Score
Vulnerability Location
Source-to-Sink Analysis
proxy_http_version 2 is a valid proxy configuration value. When selected, the normal proxy handler dispatches the request into the HTTP/2 upstream implementation.
proxy_set_body stores a configured complex value in body_source, then compiles it into body_lengths and body_values. Those script arrays can include request-derived variables, so the generated body length and bytes can depend on attacker-controlled input.
In the vulnerable HTTP/2 request builder, body_len is computed from proxy_set_body scripts and added to the initial upstream buffer size, together with one DATA frame header. No upper bound is checked against the HTTP/2 24-bit frame length field.
The vulnerable sink serializes body_len into only three length bytes, marks the DATA frame as END_STREAM, and then writes the full generated body immediately after the frame header.
The first upstream buffer is treated as preframed headers and sent as-is. Because the oversized proxy_set_body DATA frame was embedded in that same buffer, it bypassed the later output filter logic that would normally split request body data into valid HTTP/2 DATA frames.
Commit c24fb25 creates a separate body buffer for proxy_set_body output and lets the existing HTTP/2 body output filter frame it in chunks capped by NGX_HTTP_V2_DEFAULT_FRAME_SIZE and current flow-control windows.
Impact Analysis
Critical Impact
An attacker can manipulate the HTTP/2 byte stream delivered to the upstream peer. Depending on the upstream HTTP/2 implementation and the injected frame sequence, this can alter upstream request semantics, inject extra frames on the stream or connection, reset streams, or otherwise violate the proxy's intended request boundary. The CNA-scored direct impact is low integrity impact on a changed scope.
Attack Surface
NGINX Open Source deployments using the HTTP/2 upstream proxy path with proxy_http_version 2 and proxy_set_body in an affected version. The CVE record marks NGINX Open Source versions from 1.29.4 before 1.30.1 as affected, with 1.30.1 and 1.31.0 containing the fix.
Preconditions
The target location must proxy to an HTTP/2 upstream and use proxy_set_body. Practical exploitation requires the configured body expression to generate more than 16,777,215 bytes and to include attacker-controlled bytes after the wrapped DATA length boundary, for example through request-derived variables.
Proof of Concept
Environment Setup
Use an affected NGINX Open Source build from 1.29.4 before 1.30.1, or build the parent revision before c24fb25:
Target Configuration
Run a raw TCP capture service as the upstream and configure NGINX to proxy HTTP/2 with a generated body:
A simple Python TCP server that reads and saves all bytes from port 9000 is enough to observe the malformed upstream stream.
Exploit Delivery
Send a body larger than the HTTP/2 24-bit frame length limit. The three DATA length bytes encode body_len & 0xffffff, so a body of 16,777,216 + 9 bytes is advertised as a 9-byte DATA frame. Put 9 harmless bytes first, then place the injected HTTP/2 frame bytes immediately after that wrapped DATA payload boundary:
Then inspect the captured upstream bytes around the DATA frame boundary.
Outcome
The PoC demonstrates the encoding error that CVE-2026-42926 describes: oversized proxy_set_body output can escape the intended DATA payload boundary and become attacker-controlled HTTP/2 frame bytes to the upstream peer.
Expected Response:
On a vulnerable build, the initial upstream buffer contains a DATA frame whose three-byte length field is only the low 24 bits of the generated body length, while the full body bytes follow. Bytes after the declared DATA payload boundary are therefore presented to the upstream parser as additional HTTP/2 frame data. On a fixed build, the generated body is emitted by the body output filter as valid DATA frames no larger than NGX_HTTP_V2_DEFAULT_FRAME_SIZE.
