CVE-2026-9323 Overview
CVE-2026-9323 is an insecure random number generation flaw in the urwid Python library's web display backend (urwid/display/web.py). The Screen.start() function generates web session identifiers (urwid_id) by concatenating two random.randrange(10**9) calls that rely on Python's Mersenne Twister PRNG. The Mersenne Twister is not cryptographically secure, allowing attackers to reconstruct internal state and predict session identifiers. The same identifier is written as a FIFO filename in the world-listable /tmp directory, exposing active tokens to any local user. The issue is categorized under [CWE-338] Use of Cryptographically Weak PRNG.
Critical Impact
A valid session identifier lets an attacker read the victim's terminal, inject keystrokes, and execute commands with the session owner's privileges.
Affected Products
- Urwid Python library — web display backend (urwid/display/web.py)
- Applications embedding the Urwid web backend on multi-user hosts
- Deployments exposing the X-Urwid-ID HTTP response header to network clients
Discovery Timeline
- 2026-07-18 - CVE-2026-9323 published to NVD
- 2026-07-23 - Last updated in NVD database
Technical Details for CVE-2026-9323
Vulnerability Analysis
The Urwid web backend generates each session identifier from two random.randrange(10**9) calls seeded by Python's Mersenne Twister. Each call consumes approximately 30 bits of PRNG state. The Mersenne Twister maintains roughly 19,937 bits of internal state, so an attacker observing about 334 session IDs can recover the state and predict all past and future identifiers. This network-based attack path (Path B) uses the X-Urwid-ID HTTP response header to harvest samples.
A parallel local attack path (Path A) exists because Urwid writes a FIFO named after the session identifier into /tmp — for example /tmp/urwid375487765176907690.in. Any local user can list /tmp and read the active token directly without prediction. With a valid identifier, the attacker can poll the display endpoint to read the victim's terminal, inject keystrokes into the session, or flood the FIFO to crash it. When the session hosts a shell, keystroke injection yields command execution with the owner's privileges.
Root Cause
The developer used the non-cryptographic random module for a security-sensitive token. A Bandit S311 warning flagged the call site, but the warning was suppressed with # noqa: S311 instead of remediated. Placing the token in a world-listable directory compounds the flaw.
Attack Vector
Remote attackers collect roughly 334 X-Urwid-ID values, reconstruct the Mersenne Twister state, and predict future session IDs. Local attackers enumerate /tmp to read tokens directly. Either path enables session takeover through the polling and input endpoints.
# Security patch in urwid/display/web.py - Web display: tighten security
# by using more complex identifiers (#1137)
import html
import os
import pathlib
+import secrets
import selectors
import signal
import socket
import string
import sys
import tempfile
import typing
-import uuid
from contextlib import suppress
from urwid.str_util import calc_text_pos, calc_width, move_next_char
Source: GitHub Commit 24acd12f — the fix replaces uuid-based token generation with the cryptographically secure secrets module.
Detection Methods for CVE-2026-9323
Indicators of Compromise
- Files matching the pattern /tmp/urwid*.in or /tmp/urwid*.update owned by unexpected users.
- Repeated HTTP requests reading the X-Urwid-ID response header from a single source at high volume.
- Unexpected input arriving at an Urwid FIFO from processes other than the session owner.
Detection Strategies
- Instrument the web backend to log session identifier issuance and correlate against source IP request rates.
- Alert when a single client observes more than a few hundred distinct urwid_id values in a short window.
- Audit /tmp for FIFOs named urwid* and validate ownership against active sessions.
Monitoring Recommendations
- Monitor process command lines for Python applications importing urwid.display.web on multi-tenant hosts.
- Track writes to FIFO paths under /tmp/urwid*.in for writer PIDs that do not match the session owner.
- Capture HTTP access logs and flag scraping patterns targeting the polling endpoint.
How to Mitigate CVE-2026-9323
Immediate Actions Required
- Upgrade urwid to the patched release that replaces random.randrange with the secrets module for token generation.
- Remove or restrict network exposure of any application using the Urwid web display backend until patched.
- Restrict access to /tmp on multi-user hosts using per-user temporary directories or PrivateTmp=yes under systemd.
Patch Information
The upstream fix is delivered in commit 24acd12f, merged via Pull Request #1128. See the GitHub Security Advisory GHSA-rjwp-g85x-gmjv and the VulnCheck advisory for full remediation details. The patch imports secrets and removes uuid-based identifier generation.
Workarounds
- Run affected services under systemd with PrivateTmp=yes to isolate the FIFO from other local users.
- Strip or rewrite the X-Urwid-ID response header at a reverse proxy to block Path B collection.
- Restrict the web backend to localhost binding and require authenticated tunnels for remote access.
# systemd unit hardening to mitigate local /tmp enumeration
[Service]
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes
NoNewPrivileges=yes
# nginx: strip the leaky response header at the reverse proxy
# proxy_hide_header X-Urwid-ID;
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

