Skip to content

CVE-2026-34441: Verified Repro With Script Download

CVE-2026-34441: cpp-httplib HTTP Request Smuggling via Unconsumed GET Request Body

CVE-2026-34441 is verified against yhirose/cpp-httplib · github. Affected versions: <=0.38.0 per GHSA metadata. Fixed in 0.40.0. Vulnerability class: Request Smuggling. This medium reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00127.

REPRO-2026-00127 yhirose/cpp-httplib · github Request Smuggling Apr 4, 2026 CVE entry ↗ .txt
Severity
MEDIUM
CVSS
4.8
Reproduced in
61m 29s
Tool calls
300
01 · Overview

What Is CVE-2026-34441?

CVE-2026-34441 is a high-severity HTTP Request Smuggling vulnerability in cpp-httplib, a header-only C++ HTTP library, versions <= 0.38.0. The server's static file handler serves GET responses without consuming the request body, letting body bytes be reinterpreted as a new request on keep-alive connections. Pruva reproduced it (reproduction REPRO-2026-00127).

02 · Severity & CVSS

CVE-2026-34441 Severity & CVSS Score

CVE-2026-34441 is rated medium severity, with a CVSS base score of 4.8 out of 10.

MEDIUM threat level
4.8 / 10 CVSS base
Weakness CWE-444 — Inconsistent Interpretation of HTTP Requests ('HTTP Request Smuggling')

Medium — meaningful risk under specific conditions. Schedule a fix in the normal cycle.

03 · Affected Versions

Affected yhirose/cpp-httplib Versions

yhirose/cpp-httplib · github versions <=0.38.0 per GHSA metadata are affected.

How to Reproduce CVE-2026-34441

$ pruva-verify REPRO-2026-00127
or curl -O https://pruva.dev/api/v1/reproductions/REPRO-2026-00127/artifacts/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh
Run in a VM or disposable container. This exploits a real vulnerability.
06 · Proof of Reproduction

Proof of Reproduction for CVE-2026-34441

Reproduced by Pruva's autonomous agents — 300 tool calls over 1h 1m. Full root-cause analysis and the complete transcript are below.

How the agent worked 522 events · 300 tool calls · 1h 1m
1h 1mDuration
300Tool calls
215Reasoning steps
522Events
2Dead-ends
Agent activity over 1h 1m
Support
15
Hypothesis
1
Repro
334
Judge
38
Variant
129
0:0061:29

Root Cause and Exploit Chain for CVE-2026-34441

Summary

cpp-httplib versions ≤0.38.0 are vulnerable to HTTP Request Smuggling. The vulnerability occurs because the server's static file handler serves GET responses WITHOUT consuming the request body. When a GET request with a Content-Length header matches a static file mount point, the handle_file_request() function returns true and causes routing() to return early, bypassing the expect_content() check that would normally read the body. This leaves request body bytes on the TCP stream, which are then interpreted as a new HTTP request on keep-alive connections.

Impact

Package: cpp-httplib (header-only C++ HTTP library) Affected Versions: ≤0.38.0 Fixed Version: 0.40.0

Risk Level: HIGH

Consequences:

  • HTTP Request Smuggling: Arbitrary HTTP requests on keep-alive connections
  • Access Control Bypass: Smuggled requests bypass proxy-level authentication
  • Cache Poisoning: Smuggled responses cached for wrong URLs
  • Request Hijacking: Behind reverse proxy, smuggled request paired with other user's request

Root Cause

Technical Explanation

The vulnerability exists in the Server::routing() function in httplib.h:

// File handler
if ((req.method == "GET" || req.method == "HEAD") &&
    handle_file_request(req, res)) {
  return true;  // Returns early for static files
}

if (detail::expect_content(req)) {  // This is never reached for GET static files
  // Content reader handler - would read the body
  ...
}

The Bug Flow:

  1. Client sends GET request with Content-Length header and a body containing a smuggled HTTP request
  2. Server matches request to static file mount point via handle_file_request()
  3. routing() returns true immediately (early return)
  4. The expect_content() check is never executed for static file requests
  5. Request body bytes remain unread in the TCP stream
  6. Server sends response for first request and keeps connection alive
  7. Next iteration of keep-alive loop reads body bytes as a new HTTP request
  8. Server processes the smuggled request

Code Location: Server::routing() at approximately line 11542-11544 in v0.38.0

Reproduction Evidence

Our differential testing confirms the vulnerability:

v0.38.0 (Vulnerable):

  • 2 HTTP responses received from single payload
  • SECRET content leaked from smuggled request
  • Server processed 2 requests: /index.html and /secret.html
  • Total bytes received: 360 (two full HTTP responses)

v0.40.0 (Fixed):

  • 1 HTTP response received
  • No SECRET content leaked
  • Server processed 1 request: /index.html only
  • Total bytes received: 179 (single HTTP response)

Exploit Payload:

GET /index.html HTTP/1.1\r\n
Host: localhost\r\n
Content-Length: 38\r\n
Connection: keep-alive\r\n
\r\n
GET /secret.html HTTP/1.1\r\n
Host: x\r\n
\r\n

The first request (GET /index.html) has a Content-Length: 38 header pointing to the second request in the body. The vulnerable server serves /index.html without consuming the body, then the body bytes are read as a separate HTTP request on the keep-alive connection.

Fix Analysis

Version 0.40.0 properly handles the request body in one of these ways:

  1. The body is consumed before the connection is returned to the keep-alive pool
  2. The connection is closed after requests with unconsumed bodies
  3. The expect_content() check is moved earlier in the routing flow

The fix ensures that body bytes cannot be left in the stream to be misinterpreted as a new request.

Attack Scenario

  1. Attacker sends crafted request to a reverse proxy with a smuggled request in the body
  2. Proxy forwards to cpp-httplib backend (v0.38.0)
  3. Backend serves the legitimate request but doesn't consume the body
  4. Backend keeps connection alive to proxy
  5. Backend reads body as second request and processes it
  6. Second response is associated with the proxy's original request
  7. Attacker receives response for smuggled request, potentially accessing protected resources

Recommendations

  1. Upgrade to cpp-httplib v0.40.0 or later
  2. Validate Content-Length headers on GET requests at the proxy/load balancer level
  3. Disable keep-alive for requests with bodies if using affected versions
  4. Monitor for anomalous request patterns in server logs

References

CVE-2026-34441 Reproduction Transcript

The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.

Full session Replay every step — scrub the timeline or play it back.

Event 1/40
0:009:44
0:00
session startedgpt-4o · CVE-2026-34441 · 413afe30
0:12
web search
0:16
0:25
0:28
0:40
web search
0:42
web search
0:45
1:13
web search
1:16
1:42
1:45
1:48
3:07
extract_facts
no facts extracted
3:10
3:11
3:11
supportrepro
9:14
error

Unknown error

9:19
9:19
9:19
9:21
9:21
9:27
9:31
9:32
$cd /data/pruva/runs/413afe30-008f-4058-ac2a-f136b90af54a && git clone --depth 1 --branch v0.38.0 https://github.com/yhirose/cpp-httplib.git 2>&1
0.9s
Cloning into 'cpp-httplib'...
Note: switching to '6f2717e6230713484c4ee819fdd431723d29ea08'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.

If you want to create a new branch to retain commits you create, you may
9:33
9:33
9:34
9:34
9:36
9:36
9:37
9:37
9:39
9:39
9:41
9:41
$tail -100 /data/pruva/runs/413afe30-008f-4058-ac2a-f136b90af54a/cpp-httplib/example/simplesvr.cc
{"cwd":"/data/pruva/runs/413afe30-008f-4058-ac2a-f136b90af54a","duration_ms":3,"exit_code":0,"stderr":"","stdout":"  for (const auto &x : form.files) {\n    const auto &name = x.first;\n    const auto &file = x.second;\n\n    snprintf(buf, sizeof(buf), \"name: %s\\n\", name.c_str());\n    s += buf;\n\n    snprintf(buf, sizeof(buf), \"filename: %s\\n\", file.filename.c_str());\n    s += buf;\n\n    snprintf(buf, sizeof(buf), \"content type: %s\\n\", file.content_type.c_str());\n    s += buf;\n\n    snprintf(buf, sizeof(buf), \"text length: %zu\\n\", file.content.size());\n    s += buf;\n\n    s += \"----------------\\n\";\n  }\n\n  return s;\n}\n\nstring log(const Request &req, const Response &res) {\n  string s;\n  char buf[BUFSIZ];\n\n  s += \"================================\\n\";\n\n  snprintf(buf, sizeof(buf), \"%s %s %s\", req.method.c_str(),\n           req.version.c_str(), req.path.c_str());\n  s += buf;\n\n  string query;\n  for (auto it = req.params.begin(); it != req.params.end(); ++it) {\n    const auto &x = *it;\n    snprintf(buf, sizeof(buf), \"%c%s=%s\",\n             (it == req.params.begin()) ? '?' : '&', x.first.c_str(),\n             x.second.c_str());\n    query … [truncated]
9:44

Artifacts and Evidence for CVE-2026-34441

Scripts, logs, diffs, and output captured during the reproduction.

No artifacts available

08 · How to Fix

How to Fix CVE-2026-34441

Upgrade yhirose/cpp-httplib · github to 0.40.0 or later.

Coming soon

Step-by-step mitigation and hardening guidance for CVE-2026-34441 — configuration checks, workarounds where no patch exists, and how to verify you're protected — is on the way.

10 · FAQ

FAQ: CVE-2026-34441

How does the CVE-2026-34441 smuggling attack work?

An attacker sends a GET request to a static file path with a Content-Length header and a body containing a second, smuggled HTTP request. Because the server never reads that body, the leftover bytes are parsed as an independent request on the same keep-alive connection, enabling request smuggling that can bypass proxy-level access control or cause cache poisoning and request hijacking behind a reverse proxy.

Which versions of cpp-httplib are affected by CVE-2026-34441, and where is it fixed?

cpp-httplib <= 0.38.0 is affected. It is fixed in 0.40.0.

How severe is CVE-2026-34441?

High severity. It enables HTTP request smuggling, access-control bypass, cache poisoning, and request hijacking on keep-alive connections behind a reverse proxy.

How can I reproduce CVE-2026-34441?

Download the verified script from this page and run it in an isolated environment against cpp-httplib <= 0.38.0 serving static files over a keep-alive connection. Send a GET request to a static file path with a Content-Length body containing a smuggled second request and confirm the smuggled request is processed; confirm 0.40.0 consumes the body correctly.
11 · References

References for CVE-2026-34441

Authoritative sources for CVE-2026-34441 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.