From 9d3f510c7f4489c4524ec0b367368bdecd19df8a Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Sat, 4 Apr 2026 16:42:00 +0530 Subject: [PATCH] fix(esp_http_server): reject Content-Length above UINT32_MAX In httpd_parse.c, cb_headers_complete() converted the HTTP parser's content_length (uint64_t) to the request's content_len (size_t) via an unsafe cast through (int). On a 32-bit size_t target a Content-Length above 4 GiB silently truncated, enabling request smuggling where the server and an upstream proxy disagree on the body length (CWE-681). Reject any Content-Length above UINT32_MAX with 413 Content Too Large before any handler runs. UINT32_MAX is the largest body length the server can represent in size_t content_len on every target, so this is the maximum the server can support; no configuration knob is needed. Closes SEC-102 Closes SEC-229 --- components/esp_http_server/src/httpd_parse.c | 22 +++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/components/esp_http_server/src/httpd_parse.c b/components/esp_http_server/src/httpd_parse.c index bde6612dfbc..0ae44779f24 100644 --- a/components/esp_http_server/src/httpd_parse.c +++ b/components/esp_http_server/src/httpd_parse.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -371,9 +372,24 @@ static esp_err_t cb_headers_complete(http_parser *parser) return ESP_FAIL; } - /* In absence of body/chunked encoding, http_parser sets content_len to -1 */ - r->content_len = ((int)parser->content_length != -1 ? - parser->content_length : 0); + /* In absence of body/chunked encoding, http_parser sets content_len to ULLONG_MAX */ + if (parser->content_length != ULLONG_MAX) { + /* Content-Length was specified. Reject any value above UINT32_MAX: it is + * the largest body length the server can represent in r->content_len on + * every target, and rejecting larger values prevents the 64->32-bit + * truncation that would otherwise enable request smuggling (CWE-681). */ + if (parser->content_length > UINT32_MAX) { + ESP_LOGW(TAG, LOG_FMT("Content-Length %" PRIu64 + " exceeds UINT32_MAX; rejecting with 413"), + (uint64_t)parser->content_length); + parser_data->error = HTTPD_413_CONTENT_TOO_LARGE; + parser_data->status = PARSING_FAILED; + return ESP_FAIL; + } + r->content_len = (size_t)parser->content_length; + } else { + r->content_len = 0; + } ESP_LOGD(TAG, LOG_FMT("bytes read = %" PRId32 ""), parser->nread); ESP_LOGD(TAG, LOG_FMT("content length = %"NEWLIB_NANO_COMPAT_FORMAT), NEWLIB_NANO_COMPAT_CAST(r->content_len));