User Input in res.sendFile()
Passing user-controlled filenames directly to res.sendFile().
Path traversal vulnerabilities occur when user-controlled paths are passed to res.sendFile() without proper validation. Even though res.sendFile() has some built-in protections, attackers can bypass them using absolute paths or by exploiting misconfigurations, accessing files outside the intended directory and potentially exposing sensitive application files, configuration, or system files.
const express = require('express');
const app = express();
// VULNERABLE: user input directly in sendFile
app.get('/download', (req, res) => {
const filename = req.query.file;
// DANGEROUS: no root option, allows absolute paths
res.sendFile(filename, (err) => {
if (err) {
res.status(404).send('File not found');
}
});
});
app.get('/file', (req, res) => {
const file = req.params.file;
const baseDir = '/app/uploads/';
// VULNERABLE: manual concatenation without validation
res.sendFile(baseDir + file);
});
// Attack: file=/etc/passwd (absolute path)
// Attack: file=../../../etc/passwd (traversal)const express = require('express');
const path = require('path');
const app = express();
const ALLOWED_FILES = [
'document.pdf',
'image.jpg',
'report.xlsx'
];
// SECURE: use root option and validate filename
app.get('/download', (req, res) => {
const filename = req.query.file;
// Validate against allowlist
if (!ALLOWED_FILES.includes(filename)) {
return res.status(400).send('Invalid file');
}
// SAFE: root option restricts to base directory
res.sendFile(filename, {
root: path.join(__dirname, 'uploads'),
dotfiles: 'deny' // Prevent access to hidden files
}, (err) => {
if (err) {
res.status(404).send('File not found');
}
});
});
app.get('/file/:file', (req, res) => {
const file = req.params.file;
// Validate filename doesn't contain path separators
if (file.includes('/') || file.includes('\\') || file.includes('..')) {
return res.status(400).send('Invalid filename');
}
// SECURE: root option enforces base directory
res.sendFile(file, {
root: '/app/uploads',
dotfiles: 'deny'
});
});The vulnerable code passes user input directly to res.sendFile() without the root option or validation, allowing absolute paths and path traversal. The secure version validates filenames against an allowlist and uses the root option to restrict file access to a specific directory.
Passing user-controlled filenames directly to res.sendFile().
Sourcery automatically identifies path traversal via res.sendfile() in express and many other security issues in your codebase.