# Root Cause Analysis Report - 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`:

```cpp
// 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
- cpp-httplib repository: https://github.com/yhirose/cpp-httplib
- Affected version: v0.38.0
- Fixed version: v0.40.0
