Safeguard
Vulnerabilities

OWASP Path Traversal: How It Works and How to Stop It

Path traversal lets an attacker reach files outside a web app's intended directory using sequences like ../../etc/passwd — here's how it works and the fixes that actually close it.

Safeguard Research Team
Research
5 min read

OWASP path traversal is a vulnerability class where an attacker manipulates a file path input — often a query parameter or upload filename — to reach files outside the directory the application intended to expose, typically using ../ sequences to climb up the directory tree. It's one of the oldest bug classes in web security and still shows up regularly because any code path that builds a file path from user input, even indirectly, is a candidate. The fix isn't a single filter; it's controlling what the input is allowed to reference in the first place.

What does a path traversal attack actually look like?

A path traversal attack looks like a normal-seeming request with a manipulated parameter, such as GET /download?file=report.pdf becoming GET /download?file=../../../../etc/passwd. If the server-side code does something like open(BASE_DIR + user_input) without validating that the resolved path stays inside BASE_DIR, each ../ walks the process up one directory, and enough of them reach the filesystem root, from which an absolute path can read any file the application's process has permission to open. On Windows, the equivalent uses ..\ sequences and can target files like C:\Windows\win.ini as a common proof-of-concept target. Encoded variants — %2e%2e%2f, double-encoding, or null-byte tricks on older stacks — exist specifically to slip past naive string-matching filters that only look for a literal ../.

Why is this still on the OWASP radar in modern frameworks?

Path traversal persists because it isn't really a language bug — it's a design bug in how file paths get constructed, and every framework still gives developers a raw file-open API somewhere. OWASP folds this vulnerability class under Broken Access Control in the current Top 10, because path traversal is fundamentally an authorization failure: the app is granting access to a resource the user was never supposed to reach. It shows up in file download endpoints, static asset servers, log viewers, template engines that load includes by name, and image resizing services that fetch a file to process — any place where "give me file X" takes a caller-controlled string as X.

How do you actually stop directory traversal?

You stop it by resolving the requested path and checking it's still inside the allowed directory, not by blacklisting ../. Concretely:

  • Resolve the full canonical path (realpath in most languages) after joining user input to the base directory, then verify the result still starts with the base directory's canonical path — this catches encoded, double-encoded, and symlink-based bypasses that string blacklists miss.
  • Prefer an allowlist of filenames or IDs over passing raw paths at all. If the app is really serving five report types, map a short ID (report_id=3) to a server-side filename lookup instead of accepting a path fragment from the client.
  • Reject any input containing .., null bytes, or absolute path markers (/, C:\) outright when a bare filename is expected, as a defense-in-depth layer on top of canonicalization, not instead of it.
  • Run the serving process with the minimum filesystem permissions it needs, so even a successful traversal only reaches files the process account can read.

Can static analysis actually catch this before it ships?

Yes, and this is one of the categories SAST tools are genuinely good at, because the pattern — user input flowing into a file-system API without an intervening canonicalization or allowlist check — is a taint-tracking problem, which is exactly what static analysis engines are built to trace. A SAST scan run in CI on every pull request will flag a new open(), readFile(), or File() constructor call that takes tainted input, long before a pen tester or bug bounty researcher finds it in production. Combining that with SAST/DAST coverage closes both ends: static analysis catches the code pattern, dynamic testing confirms whether the running application actually exposes it through a reachable endpoint.

What does a real-world consequence of this look like?

Unpatched path traversal has led to serious breaches, not just academic findings — CVE-2021-41773, a path traversal and remote code execution flaw in Apache HTTP Server 2.4.49, allowed attackers to map URLs to files outside the expected document root and, in some configurations, execute arbitrary code, and it was exploited in the wild within days of disclosure. That case is a good reminder that path traversal is rarely "just" a file read: chained with the right server configuration, it can escalate to full compromise.

FAQ

Is path traversal the same as directory traversal?

Yes — they're used interchangeably. "Directory traversal" is the older, more literal term; "path traversal" is how OWASP and most modern documentation refer to the same vulnerability class.

Does HTTPS or authentication prevent path traversal?

No. Both operate at a different layer — path traversal is a flaw in how the application builds file paths from input, and it's exploitable by any authenticated or unauthenticated user who can reach the vulnerable endpoint.

Can path traversal happen in cloud storage APIs, not just local files?

Yes. The same pattern applies to object storage keys (like S3 paths) — if user input builds an object key without validation, an attacker can potentially reach objects outside the intended prefix, depending on bucket permissions.

What's the single best first fix if you can only do one thing?

Switch from accepting raw file paths to accepting an ID that maps to a server-side path lookup. It eliminates the entire input class rather than trying to sanitize it.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.