[PATCH 3 of 3] gRPC: length checking of request headers
Maxim Dounin
mdounin at mdounin.ru
Sat Jun 13 10:41:28 UTC 2026
# HG changeset patch
# User Maxim Dounin <mdounin at mdounin.ru>
# Date 1781347140 -10800
# Sat Jun 13 13:39:00 2026 +0300
# Node ID fe5ef747dc2e471967f816f36360013c5a7aa215
# Parent 95c3ef836da866dcdd63c611732e2abccd9fc935
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
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