HexBrain

curl · Report #3481849

HTTP/2 and HTTP/3 Header Injection in curl

N/Astatus
20upvotes
30 Dec 2025disclosed

How it was found

================================================================================ VULNERABILITY REPORT: HTTP/2 and HTTP/3 Header Injection in curl

VULNERABILITY TYPE: Response Header Injection / HTTP Response Splitting SEVERITY: HIGH (CVSS 7.5+) AFFECTED VERSIONS: curl latest (as of 2025-12-29) STATUS: 0-DAY (UNPATCHED in http2.c, curl_ngtcp2.c, curl_osslq.c)

================================================================================ EXECUTIVE SUMMARY

A critical header injection vulnerability exists in curl's HTTP/2 and HTTP/3 protocol handlers. When receiving HTTP/2 or HTTP/3 headers from a malicious server, curl directly incorporates header names and values into HTTP/1-style header strings WITHOUT validating for CR (\r), LF (\n), or null (\0) bytes.

This vulnerability was PARTIALLY FIXED on 2025-12-27 in commit 6842d4e for the QUICHE HTTP/3 backend ONLY. Three other backends remain vulnerable:

  1. lib/http2.c - HTTP/2 via nghttp2 (VULNERABLE)
  2. lib/vquic/curl_ngtcp2.c - HTTP/3 via ngtcp2 (VULNERABLE)
  3. lib/vquic/curl_osslq.c - HTTP/3 via OpenSSL QUIC (VULNERABLE)

================================================================================ TECHNICAL DETAILS

VULNERABLE CODE PATTERN:

  1. HTTP/2 (lib/http2.c, lines 1705-1717):

    /* convert to an HTTP1-style header */ curlx_dyn_reset(&ctx->scratch); result = curlx_dyn_addn(&ctx->scratch, (const char *)name, namelen); // UNVALIDATED if(!result) result = curlx_dyn_addn(&ctx->scratch, STRCONST(": ")); if(!result) result = curlx_dyn_addn(&ctx->scratch, (const char *)value, valuelen); // UNVALIDATED if(!result) result = curlx_dyn_addn(&ctx->scratch, STRCONST("\r\n"));

  2. HTTP/3 via ngtcp2 (lib/vquic/curl_ngtcp2.c, lines 1220-1229):

    curlx_dyn_reset(&ctx->scratch); result = curlx_dyn_addn(&ctx->scratch, (const char *)h3name.base, h3name.len); // UNVALIDATED if(!result) result = curlx_dyn_addn(&ctx->scratch, STRCONST(": ")); if(!result) result = curlx_dyn_addn(&ctx->scratch, (const char *)h3val.base, h3val.len); // UNVALIDATED if(!result) result = curlx_dyn_addn(&ctx->scratch, STRCONST("\r\n"));

  3. HTTP/3 via OpenSSL QUIC (lib/vquic/curl_osslq.c, lines 873-887):

    result = write_resp_raw(cf, data, h3name.base, h3name.len, FALSE); // UNVALIDATED // ... result = write_resp_raw(cf, data, h3val.base, h3val.len, FALSE); // UNVALIDATED

PATCHED CODE (curl_quiche.c, commit 6842d4e):

static bool is_valid_h3_header(const uint8_t *hdr, size_t hlen) { while(hlen--) { switch(*hdr++) { case '\n': case '\r': case '\0': return FALSE; } } return TRUE; }

// Now validates before using: if(is_valid_h3_header(value, value_len) && is_valid_h3_header(name, name_len)) { // ... process header }

================================================================================ ATTACK SCENARIO

  1. CLIENT connects to MALICIOUS SERVER using HTTP/2 or HTTP/3

  2. MALICIOUS SERVER sends an HTTP/2 or HTTP/3 response with crafted headers:

    Header Name: "X-Injected\r\nSet-Cookie: session=evil" Header Value: "foo"

    OR

    Header Name: "X-Normal" Header Value: "foo\r\nX-Injected-Header: malicious-value"

  3. CURL converts to HTTP/1-style headers WITHOUT validation:

    Result: "X-Injected\r\nSet-Cookie: session=evil: foo\r\n"

  4. APPLICATION processing these headers may:

    • Accept injected cookies (cookie injection)
    • Process injected headers as legitimate
    • Experience cache poisoning if used as a proxy/CDN
    • Have security headers bypassed

================================================================================ EXPLOITATION CONDITIONS

REQUIREMENTS:

  • Victim must connect to attacker-controlled server using HTTP/2 or HTTP/3
  • Application must process curl's response headers
  • Attacker controls the server-side HTTP/2 or HTTP/3 implementation

ATTACK VECTORS:

  1. Man-in-the-Middle with modified HTTP/2/3 responses
  2. Compromised server sending malicious headers
  3. Malicious redirect to attacker's HTTP/2/3 server

================================================================================ IMPACT ASSESSMENT

  • Cookie Injection: Attacker can set arbitrary cookies
  • Cache Poisoning: Stored responses may contain injected headers
  • Security Header Bypass: CSP, HSTS, etc. can be manipulated
  • Response Splitting: Classic HTTP response splitting attacks
  • Information Disclosure: Via crafted headers in error messages

Note: HTTP/2 has ADDITIONAL risk factor: - Line 460: nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation(o, 1); - This DISABLES RFC 9113 header validation in nghttp2!

================================================================================ RECOMMENDED FIX

Apply the same validation added to curl_quiche.c (commit 6842d4e) to:

  1. lib/http2.c - Add is_valid_header() check before line 1705
  2. lib/vquic/curl_ngtcp2.c - Add is_valid_h3_header() check before line 1220
  3. lib/vquic/curl_osslq.c - Add is_valid_h3_header() check before line 873

SUGGESTED PATCH:

// Add to each file: static bool is_valid_header(const uint8_t *hdr, size_t hlen) { while(hlen--) { switch(*hdr++) { case '\n': case '\r': case '\0': return FALSE; } } return TRUE; }

// Then validate before processing: if(!is_valid_header(name, namelen) || !is_valid_header(value, valuelen)) { // Return error or skip header return NGHTTP2_ERR_CALLBACK_FAILURE; // For HTTP/2 }

================================================================================ CVE ASSIGNMENT

This vulnerability should be assigned a CVE identifier.

Related: Commit 6842d4e (partial fix for QUICHE only) mentions issue #20101

================================================================================ TIMELINE

2025-12-27: Partial fix committed for QUICHE backend (commit 6842d4e) 2025-12-29: Discovery of same vulnerability in HTTP/2 and other HTTP/3 backends 2025-12-29: This report generated

================================================================================ RESEARCHER

Identified via static code analysis of curl source repository.

Impact

Summary:

This report was disclosed publicly on HackerOne and belongs to its author and the program. See the original