← All posts
path traversaldirectory traversalsecurityvibe codingweb security

How to Prevent Path Traversal Vulnerabilities in Your Code

O

OverMCP Team

TL;DR: A path traversal vulnerability lets attackers read arbitrary files on your server by manipulating file paths (e.g., ../../../etc/passwd). Prevent it by using a safe allowlist of permitted paths, never passing user input directly to filesystem APIs, and normalizing paths before validation. Always prefer high-level file access methods over low-level path manipulation.

What Is a Path Traversal Vulnerability?

A path traversal vulnerability (also known as directory traversal) occurs when an application uses user-supplied input to construct a file path without proper sanitization. An attacker can inject special characters like ../ (dot-dot-slash) to escape the intended directory and access or execute arbitrary files on the server.

Example attack: If your app serves files via /download?file=report.pdf, an attacker can request /download?file=../../../etc/passwd to read the system password file.

Why Vibe-Coded Apps Are Especially Vulnerable

AI coding tools like Cursor, Bolt.new, and Replit Agent generate code fast but often miss security edge cases. They might directly pass user input to functions like open(), readFile(), or path.join() without validation. This is how path traversal vulnerabilities sneak into production.

How to Prevent Path Traversal: Step-by-Step

1. Use an Allowlist of Allowed Files

The most robust defense: only serve files from a predefined list. Map a user-friendly key to a real file path.

Python (Flask) Example:

ALLOWED_FILES = {
    'report': '/var/data/report.pdf',
    'invoice': '/var/data/invoice.pdf'
}

@app.route('/download')
def download():
    key = request.args.get('file')
    if key not in ALLOWED_FILES:
        abort(404)
    return send_file(ALLOWED_FILES[key])

2. Normalize and Validate Paths

If an allowlist is impractical, normalize the final path and check it stays within a root directory.

Python Example:

import os

BASE_DIR = '/var/data'

def safe_path(user_input):
    # Resolve any '..' and symlinks
    full_path = os.path.realpath(os.path.join(BASE_DIR, user_input))
    # Ensure it starts with BASE_DIR
    if not full_path.startswith(BASE_DIR + os.sep):
        raise ValueError('Path traversal detected')
    return full_path

Node.js Example:

const path = require('path');
const BASE_DIR = '/var/data';

function safePath(userInput) {
    const fullPath = path.resolve(BASE_DIR, userInput);
    if (!fullPath.startsWith(BASE_DIR + path.sep)) {
        throw new Error('Path traversal detected');
    }
    return fullPath;
}

3. Never Trust User Input for File Operations

Avoid functions that accept raw paths from users. Instead, use database IDs or hashed filenames.

Bad: open('/uploads/' + user_input)

Good: open( get_filename_from_database(user_input) )

4. Use Built-in Security Features

Many frameworks provide secure file serving. Use them instead of custom code.

  • Flask: send_from_directory() automatically prevents traversal.
  • Express: Use express.static() with dotfiles: 'ignore'.
  • Django: FileResponse() with a validated path.
  • Express Example:

    app.use('/files', express.static('public', {
        dotfiles: 'ignore',
        index: false
    }));

    5. Limit Filesystem Permissions

    Run your app with the least privilege necessary. The OS user should only have read access to the required directory.

  • Use a dedicated non-root user.
  • Set directory permissions to 750 or 700.
  • Use chroot jails or container filesystem isolation.
  • Real-World Attack Example & Fix

    Vulnerable Code (Node.js):

    const fs = require('fs');
    const path = require('path');
    
    app.get('/read', (req, res) => {
        const filePath = path.join(__dirname, 'files', req.query.name);
        fs.readFile(filePath, 'utf8', (err, data) => {
            if (err) return res.status(500).send('Error');
            res.send(data);
        });
    });

    Attack: /read?name=../../../etc/passwd

    Fixed Code:

    const fs = require('fs');
    const path = require('path');
    
    const BASE = path.resolve(__dirname, 'files');
    
    app.get('/read', (req, res) => {
        const safeName = path.basename(req.query.name); // removes all directory components
        const filePath = path.join(BASE, safeName);
        // Ensure still inside BASE
        if (!filePath.startsWith(BASE + path.sep)) {
            return res.status(403).send('Forbidden');
        }
        fs.readFile(filePath, 'utf8', (err, data) => {
            if (err) return res.status(500).send('Error');
            res.send(data);
        });
    });

    Automated Scanning with OverMCP

    Manually auditing every file operation is tedious. Tools like OverMCP automatically scan your vibe-coded apps for path traversal and other OWASP Top 10 vulnerabilities before deployment. It integrates with your CI/CD pipeline and catches issues like unvalidated path.join() calls.

    Additional Best Practices

  • Input validation: Reject any input containing .., /, or null bytes.
  • Use chroot: Isolate the application's filesystem view.
  • Monitor logs: Watch for repeated .. patterns in logs.
  • Keep frameworks updated: Security patches often address traversal bugs.
  • FAQ

    What is a path traversal vulnerability?

    A path traversal vulnerability allows an attacker to read or write files outside the intended directory by using ../ sequences in file paths. It can lead to data exposure, code execution, or system compromise.

    How do I test for path traversal in my app?

    Try injecting ../ sequences in file parameters: ../../../etc/passwd on Linux or ..\..\..\windows\win.ini on Windows. Also try URL-encoded versions like %2e%2e%2f. Automated scanners like OverMCP can do this systematically.

    Can I prevent path traversal with input sanitization alone?

    No. Input sanitization is error-prone; attackers can use encoding, null bytes, or symlinks. The most reliable method is to use an allowlist of permitted files or normalize the final path and strictly check it against a root directory.

    Is your app secure?

    Free scan in 30 seconds. No signup needed.

    Scan My App Free