CVE Watchtower

← 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.
Severity Level
LOW(3.7)
Published Date
Oct 2, 2026
Last Modified
Oct 2, 2026
Exploitation Status
No confirmed exploitation yet
CVE Record Status
Reserved
This CVE ID is referenced in a public advisory, but the CVE Program has not published its official CVE Record yet. Full CVSS/CPE data from NVD will appear here once it does.
EPSS Score (30-Day)
Data Pending
Root Weakness (CWE)
N/A
CVSS v3.1 Base Metrics — Score 3.7
Attack VectorNetwork
Attack ComplexityHigh
Privileges RequiredNone
User InteractionNone
ScopeUnchanged
ConfidentialityNone
IntegrityLow
AvailabilityNone

Affected & Patched Versions

Affected Versions
  • 0.29.0 <= 0.50.1
Patched Versions
  • 0.51.0
🎁7-Day Free Trial — Try Pro or Team, no card required.
📧Email Delivery — Threat intel straight to your inbox.
♾️Unlimited Vendors — Track your entire stack.
🚨All New CVEs — Be the first to know.
📈EPSS Spike Alerts — Catch rising risk before it peaks.
🎯Custom EPSS/CVSS — Filter noise, focus on risk.
🛡️Exploit Intel — A 2nd confirmed-exploit signal beyond KEV.
🐙GitHub Issues — Auto-tracked, no duplicates.
📬Weekly Digest — One clean summary, not inbox spam.
🏷️Watchlist Groups — Tag alerts by team (Infra/AppSec/SOC).
💬Webhooks — Slack & Teams integration.
🔀Smart Routing — Critical alerts to one channel, rest to another.
🚫Ad-Free — Uninterrupted experience.
🎁7-Day Free Trial — Try Pro or Team, no card required.
📧Email Delivery — Threat intel straight to your inbox.
♾️Unlimited Vendors — Track your entire stack.
🚨All New CVEs — Be the first to know.
📈EPSS Spike Alerts — Catch rising risk before it peaks.
🎯Custom EPSS/CVSS — Filter noise, focus on risk.
🛡️Exploit Intel — A 2nd confirmed-exploit signal beyond KEV.
🐙GitHub Issues — Auto-tracked, no duplicates.
📬Weekly Digest — One clean summary, not inbox spam.
🏷️Watchlist Groups — Tag alerts by team (Infra/AppSec/SOC).
💬Webhooks — Slack & Teams integration.
🔀Smart Routing — Critical alerts to one channel, rest to another.
🚫Ad-Free — Uninterrupted experience.