← Back to all snippets
JAVASCRIPT

Prevent Directory Traversal Attacks in Node.js File Access

Secure your Node.js application from directory traversal vulnerabilities by sanitizing user-controlled file paths before accessing the file system, preventing unauthorized file access.

const express = require('express');
const path = require('path');
const fs = require('fs');
const app = express();

// Define a safe base directory where files can be accessed
const BASE_DIR = path.resolve(__dirname, 'data');

// Ensure the base directory exists
if (!fs.existsSync(BASE_DIR)) {
    fs.mkdirSync(BASE_DIR);
    fs.writeFileSync(path.join(BASE_DIR, 'secret.txt'), 'This is a secret file.');
    fs.writeFileSync(path.join(BASE_DIR, 'public_report.pdf'), 'Public report content.');
}

app.get('/download/:filename', (req, res) => {
    const userRequestedFilename = req.params.filename;

    // --- SECURE WAY: Resolve path and ensure it's within BASE_DIR ---
    const filePath = path.join(BASE_DIR, userRequestedFilename);
    const resolvedPath = path.resolve(filePath);

    // Crucial security check: Ensure the resolved path starts with the BASE_DIR
    if (!resolvedPath.startsWith(BASE_DIR + path.sep)) {
        // Malicious attempt to access files outside BASE_DIR
        console.warn(`Path traversal attempt detected: ${userRequestedFilename}`);
        return res.status(403).send('Access Denied: Invalid file path.');
    }

    fs.readFile(resolvedPath, (err, data) => {
        if (err) {
            console.error(`Error reading file ${resolvedPath}:`, err);
            // Be generic to avoid leaking file system structure
            return res.status(404).send('File not found or inaccessible.');
        }
        res.type(path.extname(resolvedPath)); // Set appropriate Content-Type
        res.send(data);
    });
});

// Example of insecure approach (DO NOT USE IN PRODUCTION)
app.get('/download_insecure/:filename', (req, res) => {
    const insecurePath = path.join(__dirname, req.params.filename); // Allows ../../..
    // This is highly vulnerable to path traversal
    // e.g., /download_insecure/../../../../etc/passwd
    fs.readFile(insecurePath, (err, data) => {
        if (err) return res.status(404).send('File not found (insecure example).');
        res.send(data);
    });
});

app.listen(3000, () => {
    console.log('Server running on http://localhost:3000');
    console.log('Try: http://localhost:3000/download/secret.txt');
    console.log('Try to traverse: http://localhost:3000/download/../secret.txt or /download/../../../../etc/passwd');
});
How it works: This Node.js snippet demonstrates how to prevent directory traversal (also known as path traversal) attacks. It establishes a `BASE_DIR` as the only allowed directory for file access. Before reading any file requested by a user, it uses `path.join` and `path.resolve` to construct the full path and then critically checks if the `resolvedPath` still starts with the `BASE_DIR`. This ensures that malicious inputs like `../../etc/passwd` are detected and blocked, preventing attackers from accessing files outside the intended directory.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs