Using path.join() with User Input
Using path.join() to combine base directory with unvalidated user input.
Path traversal vulnerabilities occur when Express applications use path.join() or path.resolve() with user-controlled input without proper validation. Attackers can use '../' sequences to escape the intended directory and access sensitive files. While these functions normalize paths, they don't prevent traversal outside the base directory unless explicitly validated.
const express = require('express');
const path = require('path');
const fs = require('fs');
const app = express();
const BASE_DIR = '/app/files';
// VULNERABLE: path.join normalizes but doesn't prevent traversal
app.get('/download', (req, res) => {
const filename = req.query.file;
// path.join normalizes '../' but still allows escaping BASE_DIR
const filePath = path.join(BASE_DIR, filename);
if (fs.existsSync(filePath)) {
res.sendFile(filePath);
} else {
res.status(404).send('Not found');
}
});
// Attack: /download?file=../../../etc/passwdconst express = require('express');
const path = require('path');
const fs = require('fs');
const app = express();
const BASE_DIR = '/app/files';
// SECURE: validate path stays within base directory
app.get('/download', (req, res) => {
const filename = req.query.file;
// Normalize and resolve the full path
const filePath = path.normalize(path.join(BASE_DIR, filename));
const baseDir = path.normalize(BASE_DIR);
// Validate path stays within base directory
if (!filePath.startsWith(baseDir + path.sep)) {
return res.status(400).send('Invalid path');
}
if (fs.existsSync(filePath) && fs.statSync(filePath).isFile()) {
res.sendFile(filePath);
} else {
res.status(404).send('Not found');
}
});The vulnerable code uses path.join() which normalizes the path but doesn't prevent escaping the base directory. Attackers can use '../' sequences to access files outside the intended directory. The secure version validates that the normalized path starts with the base directory, rejecting any paths that escape it.
Using path.join() to combine base directory with unvalidated user input.
Sourcery automatically identifies path traversal via path.join() and path.resolve() in express and many other security issues in your codebase.