From: Willy Tarreau Date: Wed, 21 Oct 2026 06:51:18 +0000 (+0200) Subject: MEDIUM: http: add the "short-status-code" violation exception X-Git-Tag: v3.5-dev10~85 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=8a47f9028ae1b24121d2112401180e213205abd0;p=haproxy.git MEDIUM: http: add the "short-status-code" violation exception Now by default we reject status codes shorter than 3 digits, though this exception permits to continue to accept them. There is no valid reason for accepting these and no known client currently supports them, but it has been supported due to historical reasons that are long outdated. It is expected that noone will notice, and may be candidate for backporting only to the latest LTS version after some observation time. --- diff --git a/doc/configuration.txt b/doc/configuration.txt index e57ad9098..25bae6938 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -2208,6 +2208,11 @@ acceptable-http-response-violations { [-+][,...] } risk is moderate. Only ever enable this with known clients if absolutely needed. + - "short-status-code" (response): this controls acceptance of status codes + shorter than 3 characters (e.g. "0" or "99"). A lazy regex-based parser + in a client may get confused. The risk is low. Only ever enable this with + known clients if really needed. + - "non-token-in-header-name" (both): this controls the acceptance of forbidden characters in header field names. It is often used to adapt to internally developed non-standard applications which use forbidden diff --git a/include/haproxy/http-t.h b/include/haproxy/http-t.h index 385088099..4a003f81e 100644 --- a/include/haproxy/http-t.h +++ b/include/haproxy/http-t.h @@ -211,6 +211,7 @@ enum http_violation_idx { HTTP_VIO_URL_FRAG = 0, // fragment in url ('#') HTTP_VIO_URL_NON_ASCII, // non-ASCII (>=128) in URL HTTP_VIO_STATUS_LONG, // status longer than 3 characters + HTTP_VIO_STATUS_SHORT, // status shorter than 3 characters HTTP_VIO_HDR_NAME_NON_TOK, // non-token in header name HTTP_VIO_HDR_VALUE_NUL, // NUL byte in header value HTTP_VIO_TE_BAD, // inconsistent transfer encoding diff --git a/src/h1.c b/src/h1.c index 8608c99c1..8a1d455d7 100644 --- a/src/h1.c +++ b/src/h1.c @@ -765,6 +765,16 @@ int h1_headers_to_hdr_list(char *start, const char *stop, if (likely(HTTP_IS_SPHT(*ptr))) { sl.st.c.len = ptr - sl.st.c.ptr; + if (sl.st.c.len < 3) { + /* less than 3 digits */ + if (h1m->err_pos < -1 || !(global.acc_hres_vio & (1U << HTTP_VIO_STATUS_SHORT))) { + state = H1_MSG_RPCODE; + goto http_msg_invalid; + } else if (h1m->err_pos == -1) { + /* only capture the error pointer */ + h1m->err_pos = ptr - start + skip; + } + } EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rpcode_sp, http_msg_ood, state, H1_MSG_RPCODE_SP); } diff --git a/src/http.c b/src/http.c index 3c99bd354..33b5116dd 100644 --- a/src/http.c +++ b/src/http.c @@ -1634,6 +1634,7 @@ const struct http_violation http_violations[] = { { "fragment-in-url", HTTP_VIO_URL_FRAG, HTTP_DIR_REQ }, { "non-ascii-in-url", HTTP_VIO_URL_NON_ASCII, HTTP_DIR_REQ }, { "long-status-code", HTTP_VIO_STATUS_LONG, HTTP_DIR_RES }, + { "short-status-code", HTTP_VIO_STATUS_SHORT, HTTP_DIR_RES }, { "non-token-in-header-name", HTTP_VIO_HDR_NAME_NON_TOK, HTTP_DIR_BOTH }, { "nul-in-header-value", HTTP_VIO_HDR_VALUE_NUL, HTTP_DIR_BOTH }, { "inconsistent-transfer-encoding", HTTP_VIO_TE_BAD, HTTP_DIR_RES },