[nginx] HTTP/3: kept the skipped frame length separate from data...

Maxim Dounin mdounin at mdounin.ru
Tue Oct 27 16:15:52 UTC 2026


details:   http://freenginx.org/hg/nginx/rev/75d4162de2b3
branches:  
changeset: 9596:75d4162de2b3
user:      Vadim Zhestikov <v.zhestikov at f5.com>
date:      Tue Oct 27 07:10:33 2026 +0300
description:
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.

Obtained from:
https://github.com/nginx/nginx/commit/1c173a2d8767730e678c27446138d7ae5dd6fd64

diffstat:

 src/http/v3/ngx_http_v3_parse.c |  4 +++-
 src/http/v3/ngx_http_v3_parse.h |  1 +
 2 files changed, 4 insertions(+), 1 deletions(-)

diffs (32 lines):

diff --git a/src/http/v3/ngx_http_v3_parse.c b/src/http/v3/ngx_http_v3_parse.c
--- a/src/http/v3/ngx_http_v3_parse.c
+++ b/src/http/v3/ngx_http_v3_parse.c
@@ -1831,6 +1831,8 @@ ngx_http_v3_parse_data(ngx_connection_t 
                            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;
             }
@@ -1840,7 +1842,7 @@ ngx_http_v3_parse_data(ngx_connection_t 
 
         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
--- a/src/http/v3/ngx_http_v3_parse.h
+++ b/src/http/v3/ngx_http_v3_parse.h
@@ -121,6 +121,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;
 


More information about the nginx-devel mailing list