blueredix logo
info 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/passwd and /etc/shadow to enumerate users and (if running as root) crack password hashes offline.
  • ~/.aws/credentials, ~/.ssh/id_rsa, ~/.docker/config.json for 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, unzipper do.
  • 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.

Further reading