[nginx] gRPC: length checking of request headers.

Maxim Dounin mdounin at mdounin.ru
Sat Jun 20 03:59:08 UTC 2026


details:   http://freenginx.org/hg/nginx/rev/bf2261ce8bab
branches:  
changeset: 9566:bf2261ce8bab
user:      Maxim Dounin <mdounin at mdounin.ru>
date:      Sat Jun 20 06:14:35 2026 +0300
description:
gRPC: length checking of request headers.

Similarly to HTTP/2, when serializing request headers, gRPC module
reserves NGX_HTTP_V2_INT_OCTETS (4 bytes) for string lengths, and this
implies that strings up to NGX_HTTP_V2_MAX_FIELD (~2 megabytes) can be
used.  Serializing a longer string results in additional bytes being
used for the string length, potentially resulting in buffer overrun
(though unlikely with reasonable buffer sizes, as it uses only 1 extra
byte for lengths up to ~256 megabytes).

Previously, request headers weren't checked in gRPC.  With this change,
all headers are properly checked.

Reported by Evan Hellman,
https://github.com/freenginx/nginx/issues/28

diffstat:

 src/http/modules/ngx_http_grpc_module.c |  75 +++++++++++++++++++++++++++++++++
 1 files changed, 75 insertions(+), 0 deletions(-)

diffs (134 lines):

diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c
--- a/src/http/modules/ngx_http_grpc_module.c
+++ b/src/http/modules/ngx_http_grpc_module.c
@@ -916,6 +916,15 @@ ngx_http_grpc_create_request(ngx_http_re
                        "grpc header: \":method: POST\"");
 
     } else {
+
+        if (r->method_name.len > NGX_HTTP_V2_MAX_FIELD) {
+            ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
+                          "too long grpc request header value: "
+                          "\":method: %*s...\"",
+                          256, r->method_name.data);
+            return NGX_ERROR;
+        }
+
         *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_METHOD_INDEX);
         b->last = ngx_http_v2_write_value(b->last, r->method_name.data,
                                           r->method_name.len, tmp);
@@ -941,6 +950,14 @@ ngx_http_grpc_create_request(ngx_http_re
 
     if (r->valid_unparsed_uri) {
 
+        if (r->unparsed_uri.len > NGX_HTTP_V2_MAX_FIELD) {
+            ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
+                          "too long grpc request header value: "
+                          "\":path: %*s...\"",
+                          256, r->unparsed_uri.data);
+            return NGX_ERROR;
+        }
+
         if (r->unparsed_uri.len == 1 && r->unparsed_uri.data[0] == '/') {
             *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_PATH_ROOT_INDEX);
 
@@ -969,6 +986,14 @@ ngx_http_grpc_create_request(ngx_http_re
             p = ngx_copy(p, r->args.data, r->args.len);
         }
 
+        if (p - val_tmp > NGX_HTTP_V2_MAX_FIELD) {
+            ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
+                          "too long grpc request header value: "
+                          "\":path: %*s...\"",
+                          256, val_tmp);
+            return NGX_ERROR;
+        }
+
         *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_PATH_INDEX);
         b->last = ngx_http_v2_write_value(b->last, val_tmp, p - val_tmp, tmp);
 
@@ -976,6 +1001,15 @@ ngx_http_grpc_create_request(ngx_http_re
                        "grpc header: \":path: %*s\"", p - val_tmp, val_tmp);
 
     } else {
+
+        if (r->uri.len > NGX_HTTP_V2_MAX_FIELD) {
+            ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
+                          "too long grpc request header value: "
+                          "\":path: %*s...\"",
+                          256, r->uri.data);
+            return NGX_ERROR;
+        }
+
         *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_PATH_INDEX);
         b->last = ngx_http_v2_write_value(b->last, r->uri.data,
                                           r->uri.len, tmp);
@@ -985,6 +1019,15 @@ ngx_http_grpc_create_request(ngx_http_re
     }
 
     if (!glcf->host_set) {
+
+        if (ctx->host.len > NGX_HTTP_V2_MAX_FIELD) {
+            ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
+                          "too long grpc request header value: "
+                          "\":authority: %*s...\"",
+                          256, ctx->host.data);
+            return NGX_ERROR;
+        }
+
         *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_AUTHORITY_INDEX);
         b->last = ngx_http_v2_write_value(b->last, ctx->host.data,
                                           ctx->host.len, tmp);
@@ -1045,6 +1088,14 @@ ngx_http_grpc_create_request(ngx_http_re
             return NGX_ERROR;
         }
 
+        if (key_len > NGX_HTTP_V2_MAX_FIELD) {
+            ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
+                          "too long grpc request header name: "
+                          "\"%*s...\"",
+                          256, key_tmp);
+            return NGX_ERROR;
+        }
+
         b->last = ngx_http_v2_write_name(b->last, key_tmp, key_len, tmp);
 
         e.pos = val_tmp;
@@ -1066,6 +1117,14 @@ ngx_http_grpc_create_request(ngx_http_re
             return NGX_ERROR;
         }
 
+        if (val_len > NGX_HTTP_V2_MAX_FIELD) {
+            ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
+                          "too long grpc request header value: "
+                          "\"%*s: %*s...\"",
+                          key_len, key_tmp, 256, val_tmp);
+            return NGX_ERROR;
+        }
+
         b->last = ngx_http_v2_write_value(b->last, val_tmp, val_len, tmp);
 
 #if (NGX_DEBUG)
@@ -1103,6 +1162,22 @@ ngx_http_grpc_create_request(ngx_http_re
 
             *b->last++ = 0;
 
+            if (header[i].key.len > NGX_HTTP_V2_MAX_FIELD) {
+                ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
+                              "too long grpc request header name: "
+                              "\"%*s...\"",
+                              256, header[i].key.data);
+                return NGX_ERROR;
+            }
+
+            if (header[i].value.len > NGX_HTTP_V2_MAX_FIELD) {
+                ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
+                              "too long grpc request header value: "
+                              "\"%V: %*s...\"",
+                              &header[i].key, 256, header[i].value.data);
+                return NGX_ERROR;
+            }
+
             b->last = ngx_http_v2_write_name(b->last, header[i].key.data,
                                              header[i].key.len, tmp);
 


More information about the nginx-devel mailing list