Request smuggling flaws in Pingora open-source: what changed in 0.8.0

Cloudflare has patched three vulnerabilities in the Pingora framework that could enable HTTP/1.x request smuggling in standalone deployments. The issues — tracked as CVE-2026-2833, CVE-2026-2835, and CVE-2026-2836 — were reported by Rajat Raghav (xclow3n) through Cloudflare's Bug Bounty Program and are addressed in Pingora 0.8.0.

Cloudflare states that its own CDN and customer traffic were not affected. The vulnerabilities only apply when Pingora is used as an ingress proxy exposed directly to the Internet. In such deployments, an attacker could bypass proxy-layer security controls, desync requests with backends for cross-user session or credential theft, or poison proxy caches shared with other users. Cloudflare strongly recommends upgrading Pingora deployments.

Improper upgrade handling

The first reported flaw involved the Upgrade header. When Pingora received a request containing an Upgrade header, it immediately entered a "passthrough" mode, treating all subsequent bytes on the connection as part of the upgraded stream — before the upstream server had accepted the upgrade with a 101 Switching Protocols response.

Under RFC 9110, that behavior is incorrect. If the backend replies with 200 OK instead of 101, the connection is not upgraded and subsequent bytes must still be parsed as HTTP requests. Pingora's premature passthrough allowed an attacker to pipeline a partial HTTP request after an upgrade request. The partial headers would then be forwarded verbatim to the backend, bypassing any Pingora-level ACL or WAF logic. That could poison the upstream connection so a different user's subsequent request would receive the smuggled request's response (for example, an /admin page).

GET / HTTP/1.1
Host: example.com
Upgrade: foo

GET /admin HTTP/1.1
Host: example.com
BLOG-3181 image 1
BLOG-3181 image 2
The fix makes Pingora switch to upgrade passthrough only after receiving a 101 Switching Protocols response from the upstream. Cloudflare was not exposed to this issue, the company says, because its CDN ingress proxies don't exhibit this behavior and internal clients don't pipeline HTTP/1 requests; those internal connections also disable keep-alive on upgrade requests by injecting Connection: close.

Framing confusion on HTTP/1.0 and Transfer-Encoding

The second class of attack was a classic CL.TE-style desync. In the proof of concept, Pingora interpreted a request's body length based on the absence of proper framing, while a Node.js backend interpreted the same bytes as a chunked transfer. The root cause had three parts:

  1. Pingora's chunked-encoding detection only checked whether the Transfer-Encoding header value was exactly chunked, and assumed only one such header could exist. The RFC requires only that the final transfer coding be chunked for chunked framing to apply.
  2. With an unrecognized Transfer-Encoding on an HTTP/1.0 request, Pingora fell back to treating the body as close-delimited — meaning the message body ends when the connection closes. Response bodies may be close-delimited, but request bodies never are. RFC 9112 explicitly notes this distinction.
  3. HTTP/1.0 requests carrying Transfer-Encoding are inherently invalid. RFC 9112 says to treat such messages as having faulty framing and close the connection. Parsers in nginx and hyper reject these outright to avoid ambiguous framing.
GET / HTTP/1.0
Host: example.com
Connection: keep-alive
Transfer-Encoding: identity, chunked
Content-Length: 29

0

GET /admin HTTP/1.1
X:
BLOG-3181 image 3
The fixes address each root cause: Pingora now handles multiple Transfer-Encoding headers per RFC, never treats request bodies as close-delimited, and rejects invalid Content-Length values and HTTP/1.0 requests with Transfer-Encoding. As a hardening measure, Pingora also now rejects CONNECT requests by default, since its proxy logic does not treat them as special for upgrade proxying and they carry distinct framing rules. Cloudflare's internal investigation found no traffic reaching its Pingora services that would trigger any of these misinterpretations; downstream CDN layers forward only HTTP/1.1, reject ambiguous framing, and emit at most a single Transfer-Encoding: chunked header.

Cache key collisions

The third issue was a cache poisoning risk in Pingora's naive default CacheKey implementation. That default factored in only the URI path, ignoring the host header and the upstream HTTP scheme. Two different hosts sharing the same path could therefore collide in the cache and poison each other's responses.

This affects users of the alpha proxy caching feature who relied on the default cache key. Cloudflare has removed that default entirely. The reasoning: a safe cache key depends on the application's proxy logic. If that logic rewrites the URI or method on the upstream request, the key scheme must account for that, and forcing users to define their own key makes that consideration explicit. Cloudflare's own default cache key has always incorporated a broader set of factors.

Upgrade path

Pingora users operating the framework as a proxy should upgrade to Pingora 0.8.0 as soon as possible. The release addresses the request smuggling vectors disclosed this week.

Cloudflare acknowledges the burden these vulnerabilities place on downstream users. As Pingora sees wider adoption beyond Cloudflare's own infrastructure, the project is shifting toward strict RFC compliance as the default posture. The rationale is straightforward: very few deployments need to tolerate the same breadth of malformed and non-standard traffic that Cloudflare's edge handles. Enforcing the latest RFC standards by default should reduce the security burden on Pingora users while pushing the broader Internet ecosystem toward more rigorous implementations of HTTP semantics.

Disclosure timeline

  • 2025-12-02: Upgrade-based smuggling reported via bug bounty.
  • 2026-01-13: Transfer-Encoding / HTTP/1.0 parsing issues reported.
  • 2026-01-18: Default cache key construction issue reported.
  • 2026-01-29 to 2026-02-13: Fixes validated with the reporter; further RFC-compliance work initiated.
  • 2026-02-25: Cache key default removal and additional RFC checks validated.
  • 2026-03-02: Pingora 0.8.0 released.
  • 2026-03-04: CVE advisories published.

Credits

Cloudflare credits Rajat Raghav (xclow3n) for the initial report, detailed reproductions, and validation of the fixes through the bug bounty program. The researcher has also published a companion blog post with additional technical detail.

The project also thanks the Pingora open source community for ongoing issue reports, testing, and code contributions that helped bring these fixes to release.