vuln-class-path-traversal
Path Traversal, in plain English
Path traversal lets an attacker read or write files outside the directory your application meant to expose. Often the second step on the way to a full server takeover.
What this is
Path traversal (also called directory traversal, “dot-dot-slash”,
or LFI for “local file inclusion”) is a category of bug where the
application takes a filename from the user, joins it with a base
directory, and serves the resulting file — without preventing the
user from breaking out of that directory using .. to step
upward.
A minimal example. The application does:
fs.readFile('./uploads/' + filename)
The user requests filename=../../etc/passwd. The resolved path is
/etc/passwd, and the operating system happily returns it.
Why it still happens
Modern frameworks have safe ways to serve files (sendFile(),
static-asset middleware), but plenty of code reaches for raw file
APIs in places where it shouldn’t:
- Download endpoints. “download attachment”, “export report” features that build the file path from a filename in the URL.
- Image and template loading. “use this template” or “use this background image” features that resolve a user-supplied name.
- Unzipping or extraction code. “Zip Slip” is the variation
where extracting an archive whose entries contain
..segments overwrites files outside the extraction directory. Has affected Spring, Kubernetes, and several Apache projects multiple times. - Log viewers. “show log file X” features that read a path the user controls.
What an attacker gains
The default outcome is arbitrary file read in the context of the user the service runs as:
/etc/passwdand/etc/shadowto enumerate users and (if running as root) crack password hashes offline.~/.aws/credentials,~/.ssh/id_rsa,~/.docker/config.jsonfor cloud and remote-server access.- Application config files containing database passwords, API keys, signing secrets.
- The application’s own source code, looking for further bugs.
If the bug allows arbitrary file write (rare but real —
especially in upload handlers and unzip code), the consequences
escalate sharply. Drop a webshell into the document root → full
remote code execution. Overwrite ~/.ssh/authorized_keys if the
service has a home directory → SSH access. Overwrite a startup
script → persistence after reboot.
How it gets fixed
For file-read endpoints:
- Don’t take filenames from user input at all if you can avoid it. Use opaque IDs that the server-side code translates into known files.
- If you must accept filenames from users, resolve and verify.
After joining the input with the base directory, ask the
operating system for the canonical path (
realpath(),os.path.realpath(),Path.GetFullPath()) and confirm the result still starts with the canonical path of the base directory. Reject anything that doesn’t. - Allowlist the directory contents —
safeFile = base + path.basename(input)throws away any directory parts the attacker tries to inject.
For zip/tar extraction:
- Use a library that already protects against Zip Slip — modern
versions of
commons-compress,node-tar,unzipperdo. - Or apply the same canonicalisation rule to each member’s name before extracting.
For URL-to-file resolvers:
- Decode percent-encoding and unicode normalisation before
validating. Attackers often hide
..as%2e%2e,%252e%252e(double-encoded), or unicode-encoded equivalents.
How blueredix surfaces path traversal
Path-traversal CVEs appear in CMSs (Drupal, Joomla, WordPress plugins), admin panels, file managers, and archive viewers. The scanner flags these the same way it flags any CVE — with severity, exploitation probability, and a link back to How to read a CVE.
We also run a curated set of templates that probe known-vulnerable products at known-vulnerable URLs. Findings include the specific URL and the file that came back as proof.