From 1c173a2d8767730e678c27446138d7ae5dd6fd64 Mon Sep 17 00:00:00 2001 From: Vadim Zhestikov Date: Wed, 22 Jul 2026 17:48:55 -0700 Subject: [PATCH] HTTP/3: kept the skipped frame length separate from data length ngx_http_v3_parse_data() stored the remaining length of a skipped (unknown) frame in st->length -- the same field the request body filter uses for the number of DATA payload bytes to pass on as request body. When an unknown frame was split across parser invocations, the skip was interrupted with st->length holding the skip remainder; on the next buffer the body filter, which calls the parser only while st->length == 0, treated that remainder as request body. When proxying, this could result in sending unframed bytes, potentially allowing for bypass of client_max_body_size, which is enforced only on the DATA path, or an injection. The fix is to keep unknown frame payload in a separate st->skip counter. Reported by Hansol Lee of GOTROOT. --- src/http/v3/ngx_http_v3_parse.c | 4 +++- src/http/v3/ngx_http_v3_parse.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/http/v3/ngx_http_v3_parse.c b/src/http/v3/ngx_http_v3_parse.c index 1ba08c791..573a832ef 100644 --- a/src/http/v3/ngx_http_v3_parse.c +++ b/src/http/v3/ngx_http_v3_parse.c @@ -1861,6 +1861,8 @@ ngx_http_v3_parse_data(ngx_connection_t *c, ngx_http_v3_parse_data_t *st, st->type, st->length); if (st->type != NGX_HTTP_V3_FRAME_DATA && st->length > 0) { + st->skip = st->length; + st->length = 0; st->state = sw_skip; break; } @@ -1870,7 +1872,7 @@ ngx_http_v3_parse_data(ngx_connection_t *c, ngx_http_v3_parse_data_t *st, case sw_skip: - rc = ngx_http_v3_parse_skip(b, &st->length); + rc = ngx_http_v3_parse_skip(b, &st->skip); if (rc != NGX_DONE) { return rc; } diff --git a/src/http/v3/ngx_http_v3_parse.h b/src/http/v3/ngx_http_v3_parse.h index c7e1e1ebb..3db1418da 100644 --- a/src/http/v3/ngx_http_v3_parse.h +++ b/src/http/v3/ngx_http_v3_parse.h @@ -122,6 +122,7 @@ typedef struct { ngx_uint_t state; ngx_uint_t type; ngx_uint_t length; + ngx_uint_t skip; ngx_http_v3_parse_varlen_int_t vlint; } ngx_http_v3_parse_data_t;