Mar 6, 2026·5 min read·153 visits
Pingora proxies < v0.8.0 fail to validate backend confirmation before upgrading connections (e.g., WebSockets), allowing attackers to smuggle requests past security controls by exploiting state desynchronization.
A critical HTTP request smuggling vulnerability exists in Cloudflare Pingora versions prior to v0.8.0 due to improper handling of HTTP connection upgrades. The proxy prematurely transitions to a blind tunneling state upon observing an 'Upgrade' header in a client request, without waiting for the upstream server's confirmation (101 Switching Protocols). This allows attackers to desynchronize the connection state between the proxy and the backend, enabling the smuggling of arbitrary HTTP requests that bypass security controls, WAFs, and authentication layers.
CVE-2026-2833 describes a critical implementation flaw in the HTTP protocol state machine of Cloudflare Pingora, a Rust-based framework for building programmable network services. The vulnerability is a specific variant of HTTP Request Smuggling (CWE-444) characterized by a 'Premature Upgrade' transition.
In a standard HTTP/1.1 connection upgrade (such as establishing a WebSocket), the client requests a protocol switch via the Upgrade header. RFC 9110 dictates that the proxy must only transition to tunneling mode—where it forwards raw bytes without inspection—after the upstream server explicitly accepts the upgrade with a 101 Switching Protocols response. Pingora failed to adhere to this requirement, optimistically switching to tunnel mode immediately after parsing the client's Upgrade header.
This behavior creates a desynchronization window. If an attacker sends a request requesting an upgrade followed immediately by a second 'smuggled' request, Pingora treats the smuggled bytes as opaque data belonging to the upgraded stream. If the backend server rejects the upgrade (returning a 200, 403, or 404), it remains in HTTP parsing mode and interprets the smuggled bytes as a valid, subsequent request. This effectively allows the second request to traverse the proxy without being subjected to standard security policies, rate limits, or access controls.
The root cause lies in the HttpSession::read_request logic within Pingora's connection handling module. The proxy's state machine was designed to facilitate high-performance forwarding by minimizing buffering. When the parser detected a Connection: Upgrade or Upgrade: websocket header, it flagged the session for immediate conversion to a TCP tunnel.
Specifically, the code failed to verify the upstream response code before altering the interpretation of the client's byte stream. The proxy assumed that the presence of the Upgrade header in the request was sufficient to define the connection semantics for the remainder of the session. This assumption is incorrect because the upstream server has the final authority on whether the protocol switch actually occurs.
When the proxy enters this 'blind forwarding' state prematurely, it stops delineating HTTP message boundaries. It effectively becomes a transparent pipe. Meanwhile, the upstream server, having rejected or ignored the upgrade request, continues to parse the connection as a sequence of HTTP/1.1 messages. This discrepancy—where the proxy sees a stream of bytes but the backend sees a sequence of distinct messages—is the classic condition required for request smuggling.
The remediation for CVE-2026-2833 involves enforcing a strict check on the upstream response status code before transitioning the body reader mode. The fix was introduced in commit 824bdeefc61e121cc8861de1b35e8e8f39026ecd.
Vulnerable Logic (Conceptual): Previously, the decision to upgrade was made during the request phase:
// Vulnerable: Mode decided based on request headers alone
if request.headers.contains("Upgrade") {
self.body_reader_mode = BodyMode::Tunnel;
}Fixed Logic:
The patched version introduces a was_upgraded flag and defers the mode switch until the response headers are processed. The proxy now explicitly checks for the 101 status code.
// Fixed: Check response status before switching modes
fn finish_response_body(...) {
// Only convert to tunnel if the server actually switched protocols
if response.status == 101 {
self.body_reader.convert_to_tunnel();
} else {
// Otherwise, maintain HTTP/1.1 or HTTP/1.0 semantics
self.body_reader.convert_to_until_close();
}
}This change ensures that Pingora maintains HTTP parsing visibility over the connection until the protocol upgrade is mutually agreed upon by both the client and the backend server.
To exploit this vulnerability, an attacker constructs a specially crafted HTTP pipeline containing an Upgrade request followed by a malicious payload. The attack relies on the backend server behaving normally (rejecting the upgrade) while the proxy behaves abnormally (assuming the upgrade succeeded).
Step 1: The Setup The attacker connects to the Pingora proxy and sends the following payload:
GET /socket HTTP/1.1
Host: target.com
Upgrade: websocket
Connection: Upgrade
GET /admin/delete_user?id=1 HTTP/1.1
Host: target.com
Step 2: The Desynchronization
GET /socket headers. Seeing the Upgrade header, it forwards the request to the backend and immediately switches its internal state to Tunnel. It then forwards the remaining bytes (GET /admin...) blindly, assuming they are WebSocket frames.GET /socket. Suppose the backend does not support WebSockets on this endpoint or requires authentication that is missing. It responds with 404 Not Found or 401 Unauthorized.GET /admin/delete_user... as a legitimate, new request.Step 3: The Impact
The backend executes the /admin action. Crucially, because the request originated from the proxy's IP address (which is often trusted), the backend may bypass internal IP allowlists. Furthermore, Pingora's own WAF or ACLs would have only inspected the initial /socket request, completely missing the smuggled /admin command.
The impact of this vulnerability is rated Critical (CVSS 9.3) because it fundamentally undermines the security role of the proxy. Pingora is often deployed as a gateway to enforce security policies, rate limits, and authentication checks. By bypassing these checks, attackers gain direct access to backend systems.
Security Implications:
/admin, /metrics) that are configured to be blocked by the proxy.Upgrade request or a subsequent victim's request, serving malicious content to other users.Scope: This affects standalone deployments of Pingora. Cloudflare has stated that their global CDN infrastructure was not vulnerable due to specific architectural differences in how their edge network handles connection upgrades.
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:H/SI:H/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Cloudflare Pingora Cloudflare | < 0.8.0 | 0.8.0 |
| Attribute | Detail |
|---|---|
| CVE ID | CVE-2026-2833 |
| CVSS Score | 9.3 (Critical) |
| CWE ID | CWE-444 (Inconsistent Interpretation of HTTP Requests) |
| Attack Vector | Network |
| Impact | WAF Bypass, Cache Poisoning, Authorization Bypass |
| Fix Version | v0.8.0 |
A technical analysis of CVE-2026-107397, a stored Cross-Site Scripting (XSS) vulnerability in Indico's collaborative notes editor and custom link generation fields. Prior to version 3.3.13, Marshmallow serialization schemas omitted HTML sanitization during conflict resolution, and form validators failed to enforce strict URI schemes, enabling authenticated low-privilege attackers to execute arbitrary JavaScript.
An authorization bypass vulnerability exists in the legacy session export API of Indico, an open-source event management system developed at CERN. Due to a missing object-level access check, authenticated users can bypass configuration-level restrictions to extract private session metadata (including session titles, descriptions, and list of conveners) from events that they are otherwise authorized to view.
An incomplete Server-Side Request Forgery (SSRF) validation check in Indico prior to version 3.3.13 allows authenticated event organizers to bypass outbound network restrictions. By utilizing backslash characters within crafted URLs, attackers can exploit a parser differential between the application's validator and the downstream HTTP client library to access internal network resources.
CVE-2026-107717 represents a critical prompt boundary bypass and chat role injection vulnerability in the Banks Python package (versions prior to 2.5.0). The library parses generated template outputs line-by-line, attempting to validate each segment as a JSON-serialized ChatMessage object without validating the source boundaries of the text. If an application integrates user input directly into a prompt template, a remote, unauthenticated attacker can supply multi-line inputs with structured JSON payloads. This input is then parsed as high-privilege system instructions or tool execution responses, completely hijacking downstream Large Language Model behavior.
Improper pathname limitation and link resolution (CWE-22 and CWE-59) in the banks library prior to version 2.5.1 allow local attackers to read or write arbitrary files via crafted symbolic links in the prompt directory registry.
Improper validation of dynamic class resolution within Hazelcast's Zero Config Compact Serialization allows unauthenticated clients to trigger reflective class instantiation. This flaw can be exploited to read arbitrary JVM heap or off-heap memory, crash cluster nodes, or achieve arbitrary code execution under specific classpath conditions. This issue is resolved in Hazelcast versions 5.4.5, 5.5.10, 5.6.1, and 5.7.0.