Directory Traversal
Directory traversal (also path traversal, ../ attack, dot-dot-slash) is a web vulnerability class where user-supplied input is used to build a filesystem path without adequate validation, letting an attacker step outside the intended base directory and read (or sometimes write) arbitrary files. The canonical payload climbs out of the web root:
GET /download?file=../../../../etc/passwd
Each ../ pops one directory level. The exact depth depends on where the vulnerable script sits; attackers typically over-shoot (../../../../../../etc/passwd) because extra .. sequences above the filesystem root are harmless no-ops on most systems.
Bypasses and encodings
Naive filters collapse quickly. Common evasions:
| Technique | Payload | Defeats |
|---|---|---|
| URL encoding | %2e%2e%2f | filters matching literal ../ before decoding |
| Double URL encoding | %252e%252e%252f | one decode-then-filter pass |
| Nested sequence | ....// | single-pass string replacement of ../ |
| Semicolon trick | ..;/ | Tomcat-style path normalization quirks |
| Null byte | ../../../../etc/passwd%00 | appended-suffix defenses on legacy stacks — see poison-null-byte-attack |
| Absolute path | /etc/passwd | when the app prepends a base dir but the OS honors absolute paths |
Absolute-vs-relative matters: if the code does open(BASE_DIR + user_input), a leading / in user_input may cause the OS to ignore BASE_DIR entirely — no traversal needed.
Relationship to LFI
Directory traversal is the path-construction flaw; local file inclusion (LFI) is what happens when the resolved path is then handed to a language include/require that evaluates it as code. Traversal reads files; LFI executes them. The two share payloads (../, null bytes, filter bypasses) and often the same vulnerable parameter — the distinction is the sink, not the source.
Detection
Probe parameters that take filenames (?file=, ?page=, ?download=, template/include paths) with traversal sequences aimed at known-readable files: /etc/passwd on Linux, C:\Windows\win.ini on Windows. Automated scanners (burp-suite, owasp-zap, nikto, ffuf) all ship traversal wordlists.
Defense
- Don’t build paths from user input — map to a fixed allowlist of identifiers instead.
- If input must be used, canonicalize (resolve
.., symlinks, encodings) and verify the final path stays under the expected base directory. - Run the app with least filesystem privilege; chroot or containerize to shrink the reachable filesystem.
- Strip null bytes and reject non-decodable / double-encoded input at the edge.
Related
- local-file-inclusion-attacks — the code-execution escalation of the same flaw
- poison-null-byte-attack — null-byte suffix truncation
- xxe-attacks — another file-read primitive via XML
- sql-injection-attacks — sibling input-validation failure class
Sources
- OWASP — Path Traversal Attack — alternate source; original WSTG page is dead
- PortSwigger Web Security Academy — Path Traversal
- OWASP WSTG — Testing Directory Traversal — dead link