« All posts

CVE-2026-69243 PoC: aiohttp Request Smuggling via Rejected WebSocket Upgrade

First public PoC for CVE-2026-69243, an aiohttp request smuggling flaw via rejected WebSocket upgrades causing blind handler invocation behind Nginx.

On aiohttp ≤3.14.1, a rejected WebSocket upgrade leaves the request body sitting in the parser's tail buffer, which aiohttp then feeds back in as a pipelined follow-up request. Behind the Nginx WebSocket configuration taken straight from the official docs, this produces a desync: Nginx logs a single request while aiohttp processes two. The root cause lies in the C-based llhttp parser, which signals 'skip body' for requests carrying Connection: Upgrade and Content-Length — a shortcut that only holds if the upgrade actually succeeds. When it's rejected, the body is never consumed at the application layer, and request.read() returns zero bytes, making the leftover bytes invisible to handler code.

The issue is tracked as CVE-2026-69243, disclosed via a GHSA advisory and fixed in aiohttp 3.14.2, but no public exploit existed until now. The researcher built a seven-container lab and published the first public proof-of-concept, with byte-identical payloads implemented in both Python and Rust and verified in CI. Testing also showed the smuggled request could bypass proxy-level access controls such as an Nginx location /admin { deny all; } rule.

Because the second response gets absorbed by the proxy in this topology, the practical impact is blind handler invocation rather than response leakage. For engineers running aiohttp behind reverse proxies or API gateways, mitigations include stripping upgrade-related headers at the proxy layer or upgrading to the patched 3.14.2 release.