What is Path Traversal?
Your app serves user-uploaded files from /uploads/. A request to /api/files?name=photo.jpg reads /uploads/photo.jpg. But what about /api/files?name=../../.env? If your code just concatenates the path, the server walks up two directories and hands over your environment variables — database credentials, API keys, everything.
That's path traversal. The attacker never needs to guess passwords or exploit complex logic. They just type ../ until they reach the file they want. On Linux servers, /etc/passwd is the classic proof-of-concept. In real attacks, the targets are .env, config.json, and source code files.
CWE-22 is categorized under Broken Access Control (OWASP #1) because the server is giving access to files the user was never meant to reach. It's one of the oldest web vulnerabilities — and AI-generated code still gets it wrong.
How does Path Traversal work?
The bug happens when user input flows into a file system operation without sanitization. The server builds a file path from the input, and the operating system happily resolves ../ sequences to navigate parent directories.
Here's a typical vulnerable file-serving endpoint:
// app/api/files/route.ts
import fs from 'fs/promises';
import path from 'path';
const uploadsDir = path.join(process.cwd(), 'uploads');
export async function GET(req: Request) {
const url = new URL(req.url);
const filename = url.searchParams.get('name');
// Problem: filename could be "../../.env"
// path.join resolves ../ and escapes uploadsDir
const data = await fs.readFile(
path.join(uploadsDir, filename!)
);
return new Response(data);
}// app/api/files/route.ts
import fs from 'fs/promises';
import path from 'path';
const uploadsDir = path.join(process.cwd(), 'uploads');
export async function GET(req: Request) {
const url = new URL(req.url);
const filename = url.searchParams.get('name');
// Resolve the full path and verify it stays inside uploadsDir
const resolved = path.resolve(uploadsDir, filename!);
if (!resolved.startsWith(uploadsDir + path.sep)) {
return Response.json({ error: 'Invalid path' }, { status: 400 });
}
const data = await fs.readFile(resolved);
return new Response(data);
}Why do AI tools generate Path Traversal vulnerabilities?
When you ask an AI to build a file upload or download feature, it focuses on making the file operations work. The path construction looks correct — it uses path.join and everything. But join doesn't block traversal.
- path.join looks safe but isn't. Developers and AI models both assume path.join sanitizes input. It doesn't — path.join("uploads", "../../.env") resolves to ".env" without complaint.
- File serving is treated as simple. The AI generates a clean, working endpoint in five lines. Adding path validation doubles the code. The model optimizes for brevity.
- No context about directory boundaries. The model doesn't know which directories are sensitive on your server. It can't reason about what happens when ../ escapes the uploads folder.
Path traversal is especially common in vibe-coded apps because file-serving features feel simple. The code works perfectly in testing — nobody tests with <code>../../.env</code> as a filename.
Common Path Traversal patterns
File download endpoints
/api/files?name=../../.env — the classic vector. Any endpoint that reads files based on user input.
Template or static file loading
Loading HTML templates or markdown files by name from a directory. The user controls which file gets rendered.
Log or export viewers
Admin panels that display log files by path. Attackers replace the log filename with a traversal sequence.
Encoded traversal bypasses
Using %2e%2e%2f (URL-encoded ../), ..%252f (double-encoded), or ....// to bypass naive string filtering.
How Flowpatrol detects Path Traversal
Flowpatrol probes your file-handling endpoints with real traversal payloads — the same sequences an attacker would try:
- 1Maps file-serving endpoints by crawling your app and identifying routes that accept filenames, paths, or document references.
- 2Sends traversal payloads including ../../../etc/passwd, encoded variants like %2e%2e%2f, and null-byte injections.
- 3Analyzes the response for known file signatures. If the response contains root:x:0:0 or DATABASE_URL=, the traversal worked.
- 4Reports with proof showing the exact request, what file was leaked, and the path.resolve + startsWith fix.
Most scanners check for traversal in obvious places. Flowpatrol tests every parameter that could flow into a file operation.
Related terms
Check your app for path traversal.
Flowpatrol tests your file endpoints with real traversal payloads. Five minutes. One URL.
Try it free