# @vitejs/plugin-rsc Remote Code Execution through unsafe dynamic imports in RSC server function APIs on development server

@vitejs/plugin-rsc dev server passes attacker-controlled `x-rsc-action` header and form fields to dynamic import, enabling arbitrary JS execution via data: URL modules.

- Payout: Research
- Severity: critical
- Program: @vitejs/plugin-rsc
- Found by: xdavidhu, Ry0taK
- Disclosed: 2025-12-08
- CVE: CVE-2025-67489
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-j76j-5p5g-9wfr
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-j76j-5p5g-9wfr
- Tags: area:web domain:oss domain:web impact:data-leak impact:rce kind:research platform:ghsa sev:critical tech:nodejs tech:react technique:source-review vuln:rce

**Target:** Vite RSC dev server server-function endpoints (loadServerAction/decodeReply/decodeAction)
**Root cause:** Server function APIs pass request header/body values into dynamic import() during development, so a `data:text/javascript,...` module specifier is imported and executed as code.
**Steps:**
1. Start the RSC starter app with `vite dev`
2. Send POST to `/_.rsc` with header `x-rsc-action: data:text/javascript,console.log('REMOTE CODE EXECUTION 2')# `
3. Send FormData fields `0=["$F1"]` and `1={"id":"data:text/javascript,console.log('REMOTE CODE EXECUTION 1')# "}`
4. Observe both payloads execute in the server console
**How found:** Code review of the example RSC app's server function handling showed request header/body flowing into dynamic import, prompting a test with a data: URL module specifier.
**Exploitation:** Attacker with network access to the dev server POSTs a crafted multipart body and `x-rsc-action` header containing a data: URL module; the server dynamic-imports it, executing arbitrary JS with Node.js privileges to read files, exfiltrate env vars/credentials, or pivot internally.
**Escalation:** Risk amplified when `vite --host` binds the dev server to all interfaces, exposing it beyond localhost.
**Insight:** Any dev-only code path that dynamic-imports a specifier derived from request input is RCE: try `data:text/javascript,...` module IDs in RSC/SSR action loaders, not just path traversal.

