{"id":"CVE-2026-102598","kind":"vulnerability","aliases":["CVE-2026-102598","GHSA-g6x2-hccm-hh4m"],"related":[],"title":"Werkzeug safe_join() allows Windows special device names","description":"Werkzeug's `safe_join` function allows Windows device names as filenames when they have an empty ADS marker on NTFS.\r\n\r\nThis was previously reported as https://github.com/pallets/werkzeug/security/advisories/GHSA-hgf8-39gv-g3f2, but the added filtering failed to account for the fact Windows allows special device names with an empty ADS marker, such as `NUL:`.\r\n\r\n`send_from_directory` uses `safe_join` to safely serve files at user-specified paths under a directory. If the application is running on Windows and NTFS, and the requested path ends with a special device name, the file will be opened successfully, but reading will hang indefinitely.","summary":"Werkzeug's safe_join function, used by send_from_directory, accepts Windows special device names such as NUL: when they carry an empty NTFS alternate data stream marker. On Windows with NTFS, a request for such a path opens successfully but the read hangs indefinitely, which is a denial of service rather than file disclosure.","severity":"medium","cvss":6.3,"epss":0.0037,"exploited":false,"exploited_at":null,"products":[{"name":"werkzeug","note":"<3.1.9","fixed":["3.1.9"],"affected":"< 3.1.9","ecosystem":"pypi"}],"ecosystems":["pypi"],"tags":["cwe-67","flask","package","python","werkzeug","windows"],"not_affected_if":["linux-only","no-user-supplied-paths"],"how_to_check":"- Check the installed version with `pip show werkzeug` and compare it to the affected range below.\n- Look for `send_from_directory` or `safe_join` calls in the application code that serve user-supplied paths.\n- Confirm whether the application runs on Windows with NTFS.","fix":"- `werkzeug` `3.1.9` (fixed version per the product data; affected below `3.1.9`)","status":"open","published_at":"2026-09-27T18:38:58+00:00","first_seen_at":"2026-11-09T22:53:21+00:00","triaged_at":"2026-11-09T23:01:00+00:00","updated_at":"2026-11-09T23:01:00+00:00","category":"package","confidence":0.8,"triage":{"at":"2026-11-09T23:01:00Z","model":"claude-haiku-5-5","output":{"fix":"- `werkzeug` `3.1.9` (fixed version per the product data; affected below `3.1.9`)","reach":"network","title":"Werkzeug: safe_join lets Windows device names through, file reads hang","impact":"low","summary":"Werkzeug's safe_join function, used by send_from_directory, accepts Windows special device names such as NUL: when they carry an empty NTFS alternate data stream marker. On Windows with NTFS, a request for such a path opens successfully but the read hangs indefinitely, which is a denial of service rather than file disclosure.","audience":"developers","category":"package","nicknames":[],"who_cares":["python","werkzeug","flask","windows"],"confidence":0.8,"fix_status":"available","needs_auth":"unknown","worst_case":"Requests hang indefinitely, tying up server workers on Windows","analyst_note":"","how_to_check":"- Check the installed version with `pip show werkzeug` and compare it to the affected range below.\n- Look for `send_from_directory` or `safe_join` calls in the application code that serve user-supplied paths.\n- Confirm whether the application runs on Windows with NTFS.","plain_action":"","product_name":"","needs_analyst":false,"not_affected_if":["linux-only","no-user-supplied-paths"],"who_is_affected":"Only applications that use Werkzeug's send_from_directory or safe_join on Windows with NTFS volumes, where the requested path can be attacker-controlled. The sources describe a hang on read rather than access to other files, so Linux deployments and apps that never serve user-chosen paths are unlikely to be affected.","user_interaction":"no","product_ecosystem":"","needs_special_setup":"yes","severity_if_unknown":"unknown"},"cost_usd":0.000786,"input_tokens":4837,"output_tokens":605,"severity_before":"medium"},"analyst_status":null,"analyst_note":null,"search":"'-102598':11A,19A '-2026':10A,18A '-67':22B '/pallets/werkzeug/security/advisories/ghsa-hgf8-39gv-g3f2,':110C 'accept':38B 'account':117C 'ad':99C,129C 'add':113C 'allow':4A,88C,122C 'altern':52B 'applic':154C 'carri':48B 'cve':9A,17A 'cwe':21B 'data':53B 'denial':76B 'devic':7A,41B,90C,124C,169C 'directori':37B,136C,151C 'disclosur':82B 'empti':50B,98C,128C 'end':165C 'fact':120C 'fail':115C 'file':81B,143C,172C 'filenam':93C 'filter':114C 'flask':23B 'function':32B,87C 'g6x2':14A 'ghsa':13A 'ghsa-g6x2-hccm-hh4m':12A 'github.com':109C 'github.com/pallets/werkzeug/security/advisories/ghsa-hgf8-39gv-g3f2,':108C 'hang':71B,180C 'hccm':15A 'hh4m':16A 'indefinit':72B,181C 'join':3A,31B,86C,139C 'marker':55B,100C,130C 'name':8A,42B,91C,125C,170C 'ntfs':51B,59B,102C,160C 'nul':45B,133C 'open':66B,175C 'packag':24B 'path':65B,148C,164C 'previous':105C 'python':25B 'rather':79B 'read':70B,178C 'report':106C 'request':61B,163C 'run':156C 'safe':2A,30B,85C,138C,141C 'send':35B,134C 'serv':142C 'servic':78B 'special':6A,40B,123C,168C 'specifi':147C 'stream':54B 'success':67B,176C 'use':33B,137C 'user':146C 'user-specifi':145C 'werkzeug':1A,20A,26B,28B,83C 'window':5A,27B,39B,57B,89C,121C,158C","nicknames":[],"mitigations":[],"who_affected":"Only applications that use Werkzeug's send_from_directory or safe_join on Windows with NTFS volumes, where the requested path can be attacker-controlled. The sources describe a hang on read rather than access to other files, so Linux deployments and apps that never serve user-chosen paths are unlikely to be affected.","tier":"C","verified":{},"analyst_revisit_at":null,"fix_status":"available","audience":"developers","plain_action":null,"pkeys":["werkzeug"],"ptokens":["werkzeug"],"labels":["cwe67","flask","medium","package","pypi","python","werkzeug","windows"],"campaign_type":null,"search_a":"'-102598':11A,19A '-2026':10A,18A 'allow':4A 'cve':9A,17A 'devic':7A 'g6x2':14A 'ghsa':13A 'ghsa-g6x2-hccm-hh4m':12A 'hccm':15A 'hh4m':16A 'join':3A 'name':8A 'safe':2A 'special':6A 'werkzeug':1A,20A 'window':5A","search_b":"'-67':22B 'accept':38B 'altern':52B 'carri':48B 'cwe':21B 'data':53B 'denial':76B 'devic':41B 'directori':37B 'disclosur':82B 'empti':50B 'file':81B 'flask':23B 'function':32B 'hang':71B 'indefinit':72B 'join':31B 'marker':55B 'name':42B 'ntfs':51B,59B 'nul':45B 'open':66B 'packag':24B 'path':65B 'python':25B 'rather':79B 'read':70B 'request':61B 'safe':30B 'send':35B 'servic':78B 'special':40B 'stream':54B 'success':67B 'use':33B 'werkzeug':26B,28B 'window':27B,39B,57B","search_c":"'/pallets/werkzeug/security/advisories/ghsa-hgf8-39gv-g3f2,':110C 'account':117C 'ad':99C,129C 'add':113C 'allow':88C,122C 'applic':154C 'devic':90C,124C,169C 'directori':136C,151C 'empti':98C,128C 'end':165C 'fact':120C 'fail':115C 'file':143C,172C 'filenam':93C 'filter':114C 'function':87C 'github.com':109C 'github.com/pallets/werkzeug/security/advisories/ghsa-hgf8-39gv-g3f2,':108C 'hang':180C 'indefinit':181C 'join':86C,139C 'marker':100C,130C 'name':91C,125C,170C 'ntfs':102C,160C 'nul':133C 'open':175C 'path':148C,164C 'previous':105C 'read':178C 'report':106C 'request':163C 'run':156C 'safe':85C,138C,141C 'send':134C 'serv':142C 'special':123C,168C 'specifi':147C 'success':176C 'use':137C 'user':146C 'user-specifi':145C 'werkzeug':83C 'window':89C,121C,158C","cause_entry":null,"cause_path":null,"disclosures_checked_at":null,"first_public_at":"2026-09-27T18:38:58+00:00","kev":null,"cvss_vector":"CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","cvss_by":"security-advisories@github.com","poc_count":0,"sources":[{"source":"ghsa-repo","external_id":"GHSA-g6x2-hccm-hh4m","url":"https://github.com/pallets/werkzeug/security/advisories/GHSA-g6x2-hccm-hh4m","severity":"medium","published_at":"2026-09-27T18:38:58+00:00","modified_at":"2026-09-29T15:15:58+00:00","first_seen_at":"2026-11-09T22:53:21+00:00","fetched_at":"2026-11-09T22:53:21+00:00","note":null},{"source":"ghsa","external_id":"GHSA-g6x2-hccm-hh4m","url":"https://github.com/advisories/GHSA-g6x2-hccm-hh4m","severity":"medium","published_at":"2026-10-05T23:48:39+00:00","modified_at":"2026-10-05T23:48:40+00:00","first_seen_at":"2026-11-09T22:57:50+00:00","fetched_at":"2026-11-09T22:57:50+00:00","note":null},{"source":"nvd","external_id":"CVE-2026-102598","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-102598","severity":null,"published_at":"2026-09-29T16:17:06+00:00","modified_at":"2026-09-30T19:38:27+00:00","first_seen_at":"2026-11-09T23:10:12+00:00","fetched_at":"2026-11-09T23:10:12+00:00","note":null}],"documents":[{"id":110519,"url":"https://github.com/pallets/werkzeug/security/advisories/GHSA-g6x2-hccm-hh4m","title":"Maintainer's advisory: github.com","kind":"vendor","source":"ghsa-repo","publisher":"vendor","text":null,"published_at":"2026-09-27T18:38:58+00:00","relation":"advisory","confidence":null,"note":"Maintainer's advisory: github.com"},{"id":110873,"url":"https://api.github.com/repos/pallets/werkzeug/security-advisories/GHSA-g6x2-hccm-hh4m","title":"Maintainer's advisory: api.github.com","kind":"vendor","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"advisory","confidence":null,"note":"Maintainer's advisory: api.github.com"},{"id":110875,"url":"https://github.com/pallets/werkzeug/pull/3309","title":"Patch: github.com","kind":"other","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"fix","confidence":null,"note":"Patch: github.com"},{"id":110876,"url":"https://github.com/pallets/werkzeug/commit/8d77320bcdf3a34941ec06dcf16b03c065cd21b6","title":"Patch: github.com","kind":"other","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"fix","confidence":null,"note":"Patch: github.com"},{"id":110877,"url":"https://github.com/pallets/werkzeug/releases/tag/3.1.9","title":"Release: github.com","kind":"release","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"fix","confidence":null,"note":"Release: github.com"}],"disclosures":[],"exploit_sources":[{"type":"epss","score":0.0037,"url":"https://api.first.org/data/v1/epss?cve=CVE-2026-102598"}],"notice":"Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai"}