How to Prevent Path Traversal Vulnerabilities in Your Code
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_pathNode.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.
send_from_directory() automatically prevents traversal.express.static() with dotfiles: 'ignore'.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.
750 or 700.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
.., /, or null bytes... patterns in logs.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.