From b37b5e8bcf637ef209fd1730fcf341bb1a3b50be Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sun, 24 May 2026 19:58:52 +0200 Subject: [PATCH] BUG/MEDIUM: h1: limit status codes to 3 digits by default By default, HTTP/1 status codes are not limited in the parser. However, the value is stored in a 16-bit field, meaning that it may be truncated if too large. Let's just restrict to 3-digits by default, and permit to relax the check when accept-unsafe-violations is set, provided that the value still fits in 16 bits. This could be backported to latest LTS release. --- doc/configuration.txt | 3 +++ src/h1.c | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/doc/configuration.txt b/doc/configuration.txt index ca82a7795..094ecf752 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -10027,6 +10027,9 @@ no option accept-unsafe-violations-in-http-response When this option is set, the following rules are observed: + * In H1 only, status codes longer than 3 digits but whose value fits in 16 + bits are not rejected. + * In H1 only, invalid characters, including NULL character, in header name will not be rejected; however the header will be dropped. diff --git a/src/h1.c b/src/h1.c index e1df21a50..8edc816f5 100644 --- a/src/h1.c +++ b/src/h1.c @@ -710,6 +710,16 @@ int h1_headers_to_hdr_list(char *start, const char *stop, case H1_MSG_RPCODE: http_msg_rpcode: if (likely(HTTP_IS_DIGIT(*ptr))) { + if (ptr - sl.st.c.ptr >= 3) { + /* more than 3 digits */ + if (h1m->err_pos == -1) /* only capture the error pointer */ + h1m->err_pos = ptr - start + skip; + else if (h1m->err_pos < -1 || sl.st.status >= ((uint16_t)~0 - 9) / 10) { + /* strict checks or risk of overflow */ + state = H1_MSG_RPCODE; + goto http_msg_invalid; + } + } sl.st.status = sl.st.status * 10 + *ptr - '0'; EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rpcode, http_msg_ood, state, H1_MSG_RPCODE); }