]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: h1: limit status codes to 3 digits by default
authorWilly Tarreau <w@1wt.eu>
Sun, 24 May 2026 17:58:52 +0000 (19:58 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 26 May 2026 11:13:24 +0000 (13:13 +0200)
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
src/h1.c

index ca82a77952ba50bbd92f92b08b95b83333808344..094ecf75277aef2ffb43faeecc576f0d80b9d109 100644 (file)
@@ -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.
 
index e1df21a50a48bb493e8f08e416e999cd7a93f629..8edc816f5786a41159f108261f882fc2714d38ae 100644 (file)
--- 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);
                }