chunked: reject invalid bytes in trailer

Trailers are delivered to the application as headers via
CLIENTWRITE_TRAILER, but unlike regular response headers they skipped
the verify_header() checks, so a server could smuggle a nul byte (or
stray CR) into a header reaching CURLOPT_HEADERFUNCTION and
curl_easy_header().

Run each assembled trailer line through Curl_verify_header(), the same
validation used for normal headers.

Covered by the new test 2106.

Closes #21896
This commit is contained in:
alhudz 2026-06-08 10:37:34 +05:30 committed by Daniel Stenberg
parent d69bfad3fa
commit 7de0a7e71a
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
5 changed files with 75 additions and 5 deletions

View file

@ -27,6 +27,7 @@
#include "urldata.h" /* it includes http_chunks.h */
#include "curl_trc.h"
#include "http.h" /* for Curl_verify_header */
#include "sendf.h" /* for the client write stuff */
#include "curlx/dynbuf.h"
#include "multiif.h"
@ -247,6 +248,7 @@ static CURLcode httpchunk_readwrite(struct Curl_easy *data,
there was no trailer and we move on */
if(tr) {
size_t trlen;
result = curlx_dyn_addn(&ch->trailer, STRCONST("\x0d\x0a"));
if(result) {
ch->state = CHUNK_FAILED;
@ -254,8 +256,18 @@ static CURLcode httpchunk_readwrite(struct Curl_easy *data,
return result;
}
tr = curlx_dyn_ptr(&ch->trailer);
trlen = curlx_dyn_len(&ch->trailer);
/* a trailer is delivered to the client as a header, so it must pass
the same checks as a regular response header */
result = Curl_verify_header(data, tr, trlen);
if(result) {
ch->state = CHUNK_FAILED;
ch->last_code = CHUNKE_BAD_CHUNK;
return result;
}
if(!data->set.http_te_skip) {
size_t trlen = curlx_dyn_len(&ch->trailer);
if(cw_next)
result = Curl_cwriter_write(data, cw_next,
CLIENTWRITE_HEADER |