gotchajavascriptCritical
Directory Traversal Prevention for File Serving
Viewed 0 times
directory traversalpath traversalpath.resolvebase directoryfile servearbitrary file read
Problem
When serving files based on user-supplied paths, attackers can use sequences like '../../../etc/passwd' to escape the intended directory and read arbitrary server files.
Solution
Resolve the full absolute path and verify it starts with the expected base directory before opening the file. Use path.resolve() and path.normalize() together.
Why
path.resolve() collapses all '..' segments to produce a canonical absolute path. Checking that this canonical path begins with the allowed base directory ensures the file is within bounds.
Gotchas
- Do not rely on stripping '../' from the input—URL encoding (%2e%2e%2f) and Unicode normalisation can bypass naive string replacement
- On Windows, both forward slashes and backslashes are path separators—test on the target platform
- Symlinks can escape the base directory even after path resolution—use fs.realpath() to resolve symlinks before checking
- Null bytes in file names can truncate paths in some languages; Node.js throws on null bytes in paths since v7
Code Snippets
Safe file serving with path traversal prevention
const path = require('path');
const fs = require('fs');
const BASE_DIR = path.resolve('/var/app/uploads');
app.get('/files/:filename', (req, res) => {
const requested = path.resolve(BASE_DIR, req.params.filename);
if (!requested.startsWith(BASE_DIR + path.sep) && requested !== BASE_DIR) {
return res.status(403).json({ error: 'Access denied' });
}
if (!fs.existsSync(requested)) {
return res.sendStatus(404);
}
res.sendFile(requested);
});Revisions (0)
No revisions yet.