flawopen.com/path-traversal/Javascript
How naive path.join allows directory traversal in Express/Node.js, and how to enforce directory boundary checks with path.resolve and path.sep.
Imagina un escáner de llaves de hotel programado para abrir únicamente habitaciones del segundo piso. Si un huésped escribe '../../master-safe' en el teclado de la puerta, la cerradura vulnerable sube por el pasillo y abre la caja fuerte principal del gerente.
Web Application SecurityCWE-918.CWE-918Defense-in-DepthUn endpoint acepta un nombre de archivo o identificador de recurso provisto por el usuario vía parámetro HTTP.
El atacante inyecta secuencias relativas como '../', '..%2f' o rutas absolutas en el nombre del archivo.
El backend concatena el archivo al directorio base sin resolver rutas canónicas ni validar límites seguros.
El servidor lee y transmite archivos confidenciales del sistema (/etc/passwd, claves de entorno) al atacante.
// VULNERABLE: path.join allows directory breakout
const express = require('express');
const path = require('path');
const fs = require('fs');
const app = express();
const PUBLIC_DIR = path.join(__dirname, 'public');
app.get('/download', (req, res) => {
// Attacker input: "../../etc/passwd"
const targetFile = path.join(PUBLIC_DIR, req.query.file);
// Directly pipes arbitrary system file to response!
res.sendFile(targetFile);
});
// HARDENED: Canonicalize path and assert prefix with directory separator
const express = require('express');
const path = require('path');
const fs = require('fs');
const app = express();
const PUBLIC_DIR = path.resolve(__dirname, 'public');
app.get('/download', (req, res) => {
const userInput = req.query.file;
if (!userInput || typeof userInput !== 'string') {
return res.status(400).send('Invalid file parameter');
}
// 1. Resolve to absolute path
const safePath = path.resolve(PUBLIC_DIR, userInput);
// 2. Strict boundary check: must start with base folder + separator
if (!safePath.startsWith(PUBLIC_DIR + path.sep)) {
return res.status(403).send('Forbidden: Path Traversal detected');
}
// 3. Verify file exists and is a regular file
fs.stat(safePath, (err, stats) => {
if (err || !stats.isFile()) return res.status(404).send('File not found');
res.sendFile(safePath);
});
});
path.resolve().express.static() with dotfiles: 'ignore' for static file serving.