← Back to CVE List
CVE-2026-103930NVD
Vulnerability Summary
Summary cpp-httplib's streaming client API serializes caller-controlled CRLF bytes from the `Client::open_stream` path argument into the outbound HTTP/1.1 request line. Applications that pass user-selected paths to this API can unintentionally send attacker-shaped request metadata to a backend or intermediary, because the streaming path bypasses the path-encoding guard used by the ordinary buffered send path. Affected - Project: yhirose-cpp-httplib - Repo: https://github.com/yhirose/cpp-httplib - Pinned ref: 4465e81b9f7e08e2c88cc316db8dd6ddb6dafab6 - Severity: CVSS 3.1 3.7/10 — `CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N` Root cause The public `Client::open_stream` wrapper accepts the caller's `method` and `path` values and forwards them to the implementation without rewriting the path (`httplib.h:15552`). In `ClientImpl::open_stream`, `query_path` is built directly from `path` when no params are supplied (`httplib.h:12857`), then copied into `req.path` (`httplib.h:12916`). The streaming implementation then calls `detail::write_request_line(strm, req.method, req.path)` before writing headers (`httplib.h:12923`). That serializer concatenates the method, a space, the path, and ` HTTP/1.1\r\n`, then writes the resulting bytes to the stream (`httplib.h:7383`). The ordinary buffered send path has the missing guard: it builds `path_with_query` with `detail::encode_path(path_part)` when path encoding is enabled (`httplib.h:13520`), and `encode_path` percent-encodes carriage return and newline as `%0D` and `%0A` (`httplib.h:4992`). The streaming API does not take that guarded path, so raw CRLF in the supplied request target reaches the request-line sink. Reproduction INT-web-server-cpphttplib-open-stream-crlf-request-line.zip ```bash bash ./poc/run.sh ``` ```text CPPHTTPLIB_OPEN_STREAM_CRLF_REQUEST_LINE: open_stream_path_serialized_raw_crlf ``` This fingerprint is emitted only after the loopback backend observes `Client::open_stream` send a request line split by raw CRLF from the path. A build failure or connection failure without this exact fingerprint is not this bug firing; it is an unrelated setup error. Impact The attacker model is a remote unauthenticated user whose input is forwarded by an embedding application into cpp-httplib's `Client::open_stream` path argument. Exploitation requires that application behavior plus a backend or intermediary that treats the CRLF-delimited bytes as meaningful HTTP request metadata, so the practical attack complexity is deployment-dependent. When those preconditions are met, the attacker can inject or reshape outbound request metadata sent by the vulnerable application; the demonstrated effect is integrity impact on backend-visible request data, not direct confidentiality loss or availability impact. The relevant guards are satisfied by a reachable streaming request and a raw attacker-controlled path, while the ordinary `encode_path` protection is bypassed because `open_stream` writes `req.path` directly before header validation runs. Suggested fix ```001-fix.diff diff --git a/httplib.h b/httplib.h --- a/httplib.h +++ b/httplib.h @@ -12854,7 +12854,22 @@ ClientImpl::open_stream(const std::string &method, const std::string &path, handle.response = detail::make_unique<Response>(); handle.error = Error::Success; - auto query_path = params.empty() ? path : append_query_params(path, params); + auto raw_query_path = params.empty() ? path : append_query_params(path, params); + std::string path_part, query_part; + auto query_pos = raw_query_path.find('?'); + if (query_pos != std::string::npos) { + path_part = raw_query_path.substr(0, query_pos); + query_part = raw_query_path.substr(query_pos + 1); + } else { + path_part = raw_query_path; + query_part = ""; + } + + auto query_path = path_encode_ ? detail::encode_path(path_part) : path_part; + if (!query_part.empty()) { + query_path += '?' + detail::normalize_query_string(query_part); + } + handle.connection_ = detail::make_unique<ClientConnection>(); { ``` Reported by Team Atlanta.
CVSS v3.1 Base Metrics — Score 3.7
Attack VectorNetwork
Attack ComplexityHigh
Privileges RequiredNone
User InteractionNone
ScopeUnchanged
ConfidentialityNone
IntegrityLow
AvailabilityNone
Affected & Patched Versions
- 0.29.0 <= 0.50.1
- 0.51.0