Executive brief
Werkzeug is a widely-used Python web framework utility library that includes a safe_join() function for securely serving files to users. The function fails to properly block Windows special device names (like NUL, COM1, etc.) when they appear at the end of a multi-segment file path. On Windows systems, an attacker can craft a request to a path like "example/NUL" that will cause the application to hang indefinitely when attempting to read the file, creating a denial-of-service condition.
Technical details
The vulnerability is a path traversal/special file bypass (CWE-67) in Werkzeug's safe_join() function. The function is designed to prevent access to files outside a intended directory and block Windows reserved device names, but its filtering logic failed to account for multi-segment paths where a device name appears only at the final segment (e.g., "example/NUL"). The send_from_directory() function relies on safe_join() to safely serve user-requested files. On Windows, when a path resolves to a special device name, the file opens successfully but subsequent read operations hang indefinitely, causing the worker thread to become unavailable. An attacker can trigger this via a network request to an affected web application without authentication. The vulnerability affects all versions prior to 3.1.6, which includes a proper fix.
Affected products
- Pallets Werkzeug < 3.1.6
Timeline
- 2026-02-19: disclosed: Advisory GHSA-29vq-49wr-vm6x published
- 2026-02-19: patched: Version 3.1.6 released with fix