CVE-2026-64847 Overview
CVE-2026-64847 is a resource exhaustion vulnerability in AnyIO, a high-level asynchronous concurrency and networking framework for Python that runs on top of Trio or asyncio. Versions prior to 4.14.2 start process-pool workers with standard error connected to a pipe that the parent process never drains. Worker code that writes enough attacker-influenced data to sys.stderr fills the pipe buffer and blocks before returning the standard-output protocol response. The awaiting to_process.run_sync() call then remains blocked indefinitely. The vulnerability is tracked as [CWE-770: Allocation of Resources Without Limits or Throttling].
Critical Impact
Applications running untrusted or faulty worker code that produces substantial stderr output can deadlock the AnyIO process pool, resulting in denial of service for asynchronous workloads.
Affected Products
- AnyIO versions prior to 4.14.2
- Python applications using anyio.to_process.run_sync() with untrusted worker code
- Async frameworks and services that depend on AnyIO's process-pool workers
Discovery Timeline
- 2026-09-18 - CVE-2026-64847 published to NVD
- 2026-09-24 - Last updated in NVD database
Technical Details for CVE-2026-64847
Vulnerability Analysis
AnyIO's to_process module spawns worker subprocesses to execute synchronous functions off the main event loop. The documented behavior redirects all three standard streams (stdin, stdout, stderr) to os.devnull within the worker. The implementation prior to 4.14.2 only redirected stdin and stdout, leaving stderr connected to a pipe inherited from the parent process.
The parent process never reads from that stderr pipe. On POSIX systems, pipe buffers are bounded (typically 64 KB on Linux). When worker code writes more than the buffer capacity to sys.stderr, the write() call blocks waiting for the pipe to be drained. Because the worker blocks before it can send its response frame on stdout, the parent's await on the process-pool call never completes. The result is an indefinite deadlock consuming both worker and parent resources.
Root Cause
The root cause is an incomplete stream redirection in the worker bootstrap logic in src/anyio/to_process.py. Only sys.stdin and sys.stdout were reassigned to os.devnull; sys.stderr was left attached to the inherited pipe. The pipe was neither drained by a reader thread nor closed, allowing bounded-buffer backpressure to deadlock the worker.
Attack Vector
Exploitation requires local access with the ability to influence data written to sys.stderr inside a worker function. An attacker who controls worker input, or who can trigger error paths that emit large tracebacks or diagnostic output, can reliably fill the pipe buffer. This is most impactful in applications that execute untrusted user-supplied code inside process-pool workers, or in services where error output scales with attacker-controlled input.
stdout = sys.stdout
sys.stdin = open(os.devnull)
sys.stdout = open(os.devnull, "w")
+ sys.stderr = open(os.devnull, "w")
stdout.buffer.write(b"READY\n")
while True:
Source: GitHub Commit f1b7301. The patch adds the missing sys.stderr redirection to os.devnull, matching the documented behavior and eliminating the pipe-buffer backpressure path.
Detection Methods for CVE-2026-64847
Indicators of Compromise
- Python worker subprocesses spawned by AnyIO that remain in a blocked state on write() syscalls against a pipe file descriptor.
- Async applications where to_process.run_sync() calls never complete and awaiting coroutines accumulate indefinitely.
- Growing counts of orphaned or hung Python worker processes tied to a parent using AnyIO.
Detection Strategies
- Inventory Python environments and identify installations of the anyio package at versions below 4.14.2 using pip list or software bill of materials (SBOM) tooling.
- Instrument process-pool calls with timeouts and log any invocation that exceeds an expected upper bound, treating persistent hangs as candidate deadlocks.
- Correlate worker process CPU/wall-time discrepancies where wall time grows but CPU usage remains near zero, indicative of blocked I/O.
Monitoring Recommendations
- Monitor host telemetry for long-lived Python child processes whose parent is an AnyIO-based service, and alert when lifetimes exceed configured thresholds.
- Track file-descriptor counts and pipe usage per process to detect accumulation of blocked worker pipes.
- Log and review the size of stderr output produced by worker functions handling untrusted input, since anomalously large writes are the precursor to the deadlock.
How to Mitigate CVE-2026-64847
Immediate Actions Required
- Upgrade AnyIO to version 4.14.2 or later in all Python environments that use anyio.to_process functionality.
- Audit application code paths that pass untrusted input to worker functions executed via to_process.run_sync() and constrain the volume of diagnostic output.
- Add wall-clock timeouts around process-pool invocations so a hung worker cannot indefinitely block callers.
Patch Information
The issue is fixed in AnyIO 4.14.2. The fix, tracked in Pull Request #1207 and shipped in the 4.14.2 release, redirects sys.stderr in the worker subprocess to os.devnull, matching the documented behavior. Details are also published in GitHub Security Advisory GHSA-5p39-cfhj-2xmp.
Workarounds
- In worker functions, explicitly reassign sys.stderr to open(os.devnull, "w") at the top of the worker entry point until the upgrade is applied.
- Suppress or cap stderr output produced by third-party libraries invoked inside workers by configuring logging handlers to write to files instead of the inherited stream.
- Wrap to_process.run_sync() calls with anyio.fail_after() or equivalent timeout primitives to bound blocking time and recover from suspected deadlocks.
# Upgrade AnyIO to the patched version
pip install --upgrade 'anyio>=4.14.2'
# Verify the installed version
python -c "import anyio; print(anyio.__version__)"
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

