{"id":"GHSA-p4f5-76q4-ffq7","kind":"vulnerability","aliases":["GHSA-p4f5-76q4-ffq7"],"related":[],"title":"Remote code execution using `__vite-browser-external` virtual module","description":"### Summary\r\n\r\nBy sending an HTTP request to the dev server, a arbitrary code execution was possible.\r\n\r\n### Impact\r\n\r\nOnly apps that match the following condition are affected:\r\n\r\n- explicitly exposes the Vite dev server to the network (using `--host` or [`server.host` config option](https://vitejs.dev/config/server-options.html#server-host))\r\n\r\n### Details\r\n\r\nVite's resolver plugin has `__vite-browser-external:<suffix>` virtual module and `__vite-optional-peer-dep:<suffix>` virtual module. These modules embedded the module ID, which is derived from the URL, without escaping. The `<suffix>` can be any value, so any code was able to be injected in those modules.\r\n\r\nSince Vite trusts the module code, there was two problems with this injection.\r\n\r\nFirst, the modules referenced by a module are allowed for the `server.fs` check. For example, if the attacker injects `import '/path/to/some-secret-file.txt'`, `/path/to/some-secret-file.txt` can be fetched.\r\n\r\nSecond, Vite uses `eval` to extract the value in the module code for `new Worker` and `import.meta.glob`. By using that functionality, the attacker can make Vite evaluate the injected code on the server. Vite prevents some module / global variables like `exports`, `require` to avoid bugs, but because this is not a security boundary, there's a bypass like `globalThis.process.getBuiltinModule`.\r\n\r\n### PoC\r\n\r\n```sh\r\nprintf 'CANARY-SECRET-not-valid-js\\n' > /tmp/decoy-secret.txt   # outside the project\r\nvite\r\n```\r\n`/tmp/decoy-secret.txt` stands in for any sensitive file outside the allow list.\r\n\r\n1. Check that the target is correctly blocked. `GET /@fs/tmp/decoy-secret.txt` returns 403 Restricted (\"outside of Vite serving allow list\").\r\n2. Perform the injection. Send a request carrying the crafted id (it is shown decoded. \\n are real newlines in the sent URL, percent-encoded on the wire):\r\n   ```\r\n   GET /@id/__vite-browser-external:`);}});\r\n   import '/@fs/tmp/decoy-secret.txt';\r\n   var z=new Proxy({}, {get(_, key) {throw new Error(`?import\r\n   ```\r\n   This pulls `/tmp/decoy-secret.txt` into the module graph.\r\n3. Extract the file. `GET /@fs/tmp/decoy-secret.txt` returns the content in the body (`CANARY-SECRET-not-valid-js`).\r\n\r\n### Notes on the fixes\r\n\r\nThe vulnerable code in v8 lives in the Rolldown binary. The code is only meant to be used by Vite and thus the report is not linked to Rolldown. Vite 8.3.7 and Vite 8.2.5 relies on the fix in Rolldown 1.2.17. Vite 8.1.7 relies on the fix in Rolldown 1.1.7.","summary":"A crafted HTTP request to the Vite dev server injects code into a virtual module, which the server then evaluates. An attacker can run code on the machine and read files outside the allowed serving list.","severity":"critical","cvss":9.1,"epss":null,"exploited":false,"exploited_at":null,"products":[{"name":"vite","note":">=8.3.0,<=8.3.6","fixed":["8.3.7"],"affected":">= 8.3.0, <= 8.3.6","ecosystem":"npm"},{"name":"vite","note":">=8.2.0,<=8.2.4","fixed":["8.2.5"],"affected":">= 8.2.0, <= 8.2.4","ecosystem":"npm"},{"name":"vite","note":">=8.0.0,<=8.1.6","fixed":["8.1.7"],"affected":">= 8.0.0, <= 8.1.6","ecosystem":"npm"},{"name":"vite","note":">=7.0.0,<=7.3.7","fixed":["7.3.8"],"affected":">= 7.0.0, <= 7.3.7","ecosystem":"npm"},{"name":"vite","note":">= 4.0.0,<=6.4.5","fixed":["6.4.6"],"affected":">= 4.0.0, <= 6.4.5","ecosystem":"npm"},{"name":"vite-plus","note":"<=1.5.0","fixed":["1.5.1"],"affected":"<= 1.5.0","ecosystem":"npm"}],"ecosystems":["npm"],"tags":["cwe-116","dev-server","npm","package","vite","vite-plus"],"not_affected_if":["default-config","localhost-only-dev-server","production-build-only"],"how_to_check":"- Run `npm ls vite` in the project and compare the installed version with the fixed versions below.\n- Check whether the dev server is started with `--host` or has `server.host` set in the Vite config, since only exposed servers are affected.","fix":"- `vite` 8.3.7 for the 8.3.x line\n- `vite` 8.2.5 for the 8.2.x line\n- `vite` 8.1.7 for the 8.1.x line\n- `vite` 7.3.8 for the 7.x line\n- `vite` 6.4.6 for the 4.x to 6.x range\n- `vite-plus` 1.5.1 for versions up to 1.5.0","status":"open","published_at":"2026-11-10T01:35:55+00:00","first_seen_at":"2026-11-10T01:42:36+00:00","triaged_at":"2026-11-10T01:44:35+00:00","updated_at":"2026-11-10T01:44:35+00:00","category":"package","confidence":0.9,"triage":{"at":"2026-11-10T01:44:35Z","model":"claude-haiku-5-5","output":{"fix":"- `vite` 8.3.7 for the 8.3.x line\n- `vite` 8.2.5 for the 8.2.x line\n- `vite` 8.1.7 for the 8.1.x line\n- `vite` 7.3.8 for the 7.x line\n- `vite` 6.4.6 for the 4.x to 6.x range\n- `vite-plus` 1.5.1 for versions up to 1.5.0","reach":"network","title":"Vite: dev server request injection leads to remote code execution","impact":"high","summary":"A crafted HTTP request to the Vite dev server injects code into a virtual module, which the server then evaluates. An attacker can run code on the machine and read files outside the allowed serving list.","audience":"developers","category":"package","nicknames":[],"who_cares":["vite","vite-plus","npm","dev-server"],"confidence":0.9,"fix_status":"available","needs_auth":"no","worst_case":"Attacker runs code on the server and reads arbitrary local files.","analyst_note":"","how_to_check":"- Run `npm ls vite` in the project and compare the installed version with the fixed versions below.\n- Check whether the dev server is started with `--host` or has `server.host` set in the Vite config, since only exposed servers are affected.","plain_action":"","product_name":"","needs_analyst":false,"not_affected_if":["localhost-only-dev-server","production-build-only","default-config"],"who_is_affected":"Only projects that run the Vite dev server reachable from the network, either with the `--host` flag or with `server.host` set in the config. Dev servers bound to localhost only, and production builds, are not exposed by this flaw. Teams should patch any developer machine or shared dev environment that exposes the server.","user_interaction":"no","product_ecosystem":"","needs_special_setup":"yes","severity_if_unknown":"critical"},"cost_usd":0.000879,"input_tokens":5660,"output_tokens":626,"severity_before":"critical"},"analyst_status":null,"analyst_note":null,"search":"'-116':30B '/config/server-options.html#server-host))':119C '/path/to/some-secret-file.txt':203C,204C '/tmp/decoy-secret.txt':277C,282C,357C '1':293C '1.1.7':433C '1.2.17':424C '2':312C '3':362C '403':304C '76q4':14A,19A '8.1.7':426C '8.2.5':417C '8.3.7':414C 'abl':163C 'affect':101C 'allow':73B,191C,291C,310C 'app':94C 'arbitrari':87C 'attack':61B,200C,230C 'avoid':251C 'binari':393C 'block':300C 'bodi':373C 'boundari':260C 'browser':7A,128C 'bug':252C 'bypass':264C 'canari':271C,375C 'canary-secret-not-valid-j':270C,374C 'carri':319C 'check':195C,294C 'code':2A,50B,64B,88C,161C,175C,219C,237C,386C,395C 'condit':99C 'config':115C 'content':370C 'correct':299C 'craft':41B,321C 'cwe':29B 'decod':326C 'dep':137C 'deriv':148C 'detail':120C 'dev':32B,47B,84C,106C 'dev-serv':31B 'embed':142C 'encod':337C 'error':353C 'escap':153C 'eval':211C 'evalu':59B,234C 'exampl':197C 'execut':3A,89C 'explicit':102C 'export':248C 'expos':103C 'extern':8A,129C 'extract':213C,363C 'fetch':207C 'ffq7':15A,20A 'file':70B,288C,365C 'first':183C 'fix':383C,421C,430C 'follow':98C 'fs/tmp/decoy-secret.txt':302C,344C,367C 'function':228C 'get':301C,341C,349C,366C 'ghsa':12A,17A 'ghsa-p4f5-76q4-ffq7':11A,16A 'global':245C 'globalthis.process.getbuiltinmodule':266C 'graph':361C 'host':112C 'http':42B,80C 'id':145C,322C 'id/__vite-browser-external':342C 'impact':92C 'import':202C,343C,354C 'import.meta.glob':224C 'inject':49B,166C,182C,201C,236C,315C 'js':275C,379C 'key':350C 'like':247C,265C 'link':410C 'list':75B,292C,311C 'live':389C 'machin':67B 'make':232C 'match':96C 'meant':398C 'modul':10A,54B,131C,139C,141C,144C,169C,174C,185C,189C,218C,244C,360C 'n':276C,327C 'network':110C 'new':221C,347C,352C 'newlin':330C 'note':380C 'npm':34B 'option':116C,135C 'outsid':71B,278C,289C,306C 'p4f5':13A,18A 'packag':35B 'peer':136C 'percent':336C 'percent-encod':335C 'perform':313C 'plugin':124C 'plus':28A,39B 'poc':267C 'possibl':91C 'prevent':242C 'printf':269C 'problem':179C 'project':280C 'proxi':348C 'pull':356C 'read':69B 'real':329C 'referenc':186C 'reli':418C,427C 'remot':1A 'report':407C 'request':43B,81C,318C 'requir':249C 'resolv':123C 'restrict':305C 'return':303C,368C 'rolldown':392C,412C,423C,432C 'run':63B 'second':208C 'secret':272C,376C 'secur':259C 'send':78C,316C 'sensit':287C 'sent':333C 'serv':74B,309C 'server':33B,48B,57B,85C,107C,240C 'server.fs':194C 'server.host':114C 'sh':268C 'shown':325C 'sinc':170C 'stand':283C 'summari':76C 'target':297C 'throw':351C 'thus':405C 'trust':172C 'two':178C 'url':151C,334C 'use':4A,111C,210C,226C,401C 'v8':388C 'valid':274C,378C 'valu':158C,215C 'var':345C 'variabl':246C 'virtual':9A,53B,130C,138C 'vite':6A,21A,22A,23A,24A,25A,27A,36B,38B,46B,105C,121C,127C,134C,171C,209C,233C,241C,281C,308C,403C,413C,416C,425C 'vite-browser-extern':5A,126C 'vite-optional-peer-dep':133C 'vite-plus':26A,37B 'vitejs.dev':118C 'vitejs.dev/config/server-options.html#server-host))':117C 'vulner':385C 'wire':340C 'without':152C 'worker':222C 'z':346C","nicknames":[],"mitigations":[],"who_affected":"Only projects that run the Vite dev server reachable from the network, either with the `--host` flag or with `server.host` set in the config. Dev servers bound to localhost only, and production builds, are not exposed by this flaw. Teams should patch any developer machine or shared dev environment that exposes the server.","tier":"B","verified":{},"analyst_revisit_at":null,"fix_status":"available","audience":"developers","plain_action":null,"pkeys":["vite","viteplus"],"ptokens":["plus","vite"],"labels":["critical","cwe116","devserver","npm","package","vite","viteplus"],"campaign_type":null,"search_a":"'76q4':14A,19A 'browser':7A 'code':2A 'execut':3A 'extern':8A 'ffq7':15A,20A 'ghsa':12A,17A 'ghsa-p4f5-76q4-ffq7':11A,16A 'modul':10A 'p4f5':13A,18A 'plus':28A 'remot':1A 'use':4A 'virtual':9A 'vite':6A,21A,22A,23A,24A,25A,27A 'vite-browser-extern':5A 'vite-plus':26A","search_b":"'-116':30B 'allow':73B 'attack':61B 'code':50B,64B 'craft':41B 'cwe':29B 'dev':32B,47B 'dev-serv':31B 'evalu':59B 'file':70B 'http':42B 'inject':49B 'list':75B 'machin':67B 'modul':54B 'npm':34B 'outsid':71B 'packag':35B 'plus':39B 'read':69B 'request':43B 'run':63B 'serv':74B 'server':33B,48B,57B 'virtual':53B 'vite':36B,38B,46B 'vite-plus':37B","search_c":"'/config/server-options.html#server-host))':119C '/path/to/some-secret-file.txt':203C,204C '/tmp/decoy-secret.txt':277C,282C,357C '1':293C '1.1.7':433C '1.2.17':424C '2':312C '3':362C '403':304C '8.1.7':426C '8.2.5':417C '8.3.7':414C 'abl':163C 'affect':101C 'allow':191C,291C,310C 'app':94C 'arbitrari':87C 'attack':200C,230C 'avoid':251C 'binari':393C 'block':300C 'bodi':373C 'boundari':260C 'browser':128C 'bug':252C 'bypass':264C 'canari':271C,375C 'canary-secret-not-valid-j':270C,374C 'carri':319C 'check':195C,294C 'code':88C,161C,175C,219C,237C,386C,395C 'condit':99C 'config':115C 'content':370C 'correct':299C 'craft':321C 'decod':326C 'dep':137C 'deriv':148C 'detail':120C 'dev':84C,106C 'embed':142C 'encod':337C 'error':353C 'escap':153C 'eval':211C 'evalu':234C 'exampl':197C 'execut':89C 'explicit':102C 'export':248C 'expos':103C 'extern':129C 'extract':213C,363C 'fetch':207C 'file':288C,365C 'first':183C 'fix':383C,421C,430C 'follow':98C 'fs/tmp/decoy-secret.txt':302C,344C,367C 'function':228C 'get':301C,341C,349C,366C 'global':245C 'globalthis.process.getbuiltinmodule':266C 'graph':361C 'host':112C 'http':80C 'id':145C,322C 'id/__vite-browser-external':342C 'impact':92C 'import':202C,343C,354C 'import.meta.glob':224C 'inject':166C,182C,201C,236C,315C 'js':275C,379C 'key':350C 'like':247C,265C 'link':410C 'list':292C,311C 'live':389C 'make':232C 'match':96C 'meant':398C 'modul':131C,139C,141C,144C,169C,174C,185C,189C,218C,244C,360C 'n':276C,327C 'network':110C 'new':221C,347C,352C 'newlin':330C 'note':380C 'option':116C,135C 'outsid':278C,289C,306C 'peer':136C 'percent':336C 'percent-encod':335C 'perform':313C 'plugin':124C 'poc':267C 'possibl':91C 'prevent':242C 'printf':269C 'problem':179C 'project':280C 'proxi':348C 'pull':356C 'real':329C 'referenc':186C 'reli':418C,427C 'report':407C 'request':81C,318C 'requir':249C 'resolv':123C 'restrict':305C 'return':303C,368C 'rolldown':392C,412C,423C,432C 'second':208C 'secret':272C,376C 'secur':259C 'send':78C,316C 'sensit':287C 'sent':333C 'serv':309C 'server':85C,107C,240C 'server.fs':194C 'server.host':114C 'sh':268C 'shown':325C 'sinc':170C 'stand':283C 'summari':76C 'target':297C 'throw':351C 'thus':405C 'trust':172C 'two':178C 'url':151C,334C 'use':111C,210C,226C,401C 'v8':388C 'valid':274C,378C 'valu':158C,215C 'var':345C 'variabl':246C 'virtual':130C,138C 'vite':105C,121C,127C,134C,171C,209C,233C,241C,281C,308C,403C,413C,416C,425C 'vite-browser-extern':126C 'vite-optional-peer-dep':133C 'vitejs.dev':118C 'vitejs.dev/config/server-options.html#server-host))':117C 'vulner':385C 'wire':340C 'without':152C 'worker':222C 'z':346C","cause_entry":null,"cause_path":null,"disclosures_checked_at":null,"first_public_at":"2026-11-10T01:35:55+00:00","kev":null,"cvss_vector":null,"cvss_by":null,"poc_count":0,"sources":[{"source":"ghsa-repo","external_id":"GHSA-p4f5-76q4-ffq7","url":"https://github.com/vitejs/vite/security/advisories/GHSA-p4f5-76q4-ffq7","severity":"critical","published_at":"2026-11-10T01:35:55+00:00","modified_at":"2026-11-10T01:35:55+00:00","first_seen_at":"2026-11-10T01:42:36+00:00","fetched_at":"2026-11-10T02:49:57+00:00","note":null}],"documents":[{"id":112486,"url":"https://github.com/vitejs/vite/security/advisories/GHSA-p4f5-76q4-ffq7","title":"Maintainer's advisory: github.com","kind":"vendor","source":"ghsa-repo","publisher":"vendor","text":null,"published_at":null,"relation":"advisory","confidence":null,"note":"Maintainer's advisory: github.com"}],"disclosures":[],"exploit_sources":[],"notice":"Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai"}