Blog · E.28 · Technical

Directory / path traversal explained

A feature that serves a file based on a name in the URL looks harmless - until an attacker replaces the name with ../../../etc/passwd and walks straight out of the intended folder to read your config, your credentials, your source. That's directory traversal, and it turns a download link into a filesystem-reading tool. Here's how it works, what an attacker reaches, the bypasses that defeat naive filters, how to test, and how to prevent it properly.

Path Traversal../File DisclosureLFIWeb AppSec
Path traversal: ../ Escapes the Directory · Read Config / Credentials / Source · Encoding Bypasses · Sometimes Write Files · Fix = Safe Path Construction, Not Filtering Path traversal: ../ Escapes the Directory · Read Config / Credentials / Source · Encoding Bypasses · Sometimes Write Files · Fix = Safe Path Construction, Not Filtering
// TL;DR

Directory traversal (path traversal) lets an attacker read files outside the intended directory by putting traversal sequences (../) into a file path built from user input. It exposes config, credentials, source, keys and system files - and where the app writes by path, can create/overwrite files (more severe). Reading config + credentials is the usual goal because it enables further compromise. Attackers bypass naive filters with URL/double encoding, mixed separators, absolute paths, and nested sequences - so blocklisting ../ is unreliable. The fix: don't build paths from input (map an identifier to a known file), or resolve the final absolute path and confirm it stays within the base directory; plus allow-lists and least privilege. Safe path handling, not pattern filtering. Detail below; part of every web app test.

// 01 How path traversal works

Lots of features build a file path from user input: serving a download by filename, loading a template or language file, reading an uploaded image, generating a report from a named file. The app takes something like ?file=report.pdf and constructs a path /var/app/files/report.pdf. The vulnerability appears when that input isn't properly validated: an attacker supplies traversal sequences - ../ means “go up one directory” - so ?file=../../../../etc/passwd builds a path that climbs out of the intended folder and lands on an arbitrary file anywhere the app can read. The application faithfully opens it and returns the contents. The name says it all: the attacker traverses the directory tree using the app's own file-reading feature. It's the same trust-boundary failure as the injection classes - user input controlling something (here, which file) it should never fully control.

// 02 What an attacker reaches

Traversal exposes anything the application's account can read. The high-value targets: application configuration files - which frequently hold database credentials and secrets; environment and settings files; source code (which reveals more vulnerabilities); private keys and certificates; and system files like /etc/passwd. Reading config and credentials is usually the real goal, because it enables further compromise - leaked database credentials let the attacker reach the data directly, turning a file-read into a full breach. Because a single traversal flaw can expose the secrets that protect everything else, it's typically rated high, and it becomes critical when it exposes credentials or - in the writable variant - lets an attacker create or overwrite files (which can chain to code execution). It's closely related to the file-read impact of XXE, reached a different way.

// 03 The bypasses that defeat naive filters

01

Encoding

URL-encoded or double-encoded traversal sequences slip past a filter looking for the literal ../.

02

Mixed separators

Platform-specific and mixed path separators and variants that the filter doesn't anticipate.

03

Absolute paths

Where allowed, supply an absolute path directly instead of traversing.

04

Nested sequences

Abuse code that strips one instance of ../ but not nested ones.

The lesson is blunt: trying to blocklist the traversal sequence is unreliable, because there are too many encodings and variations. Robust prevention doesn't depend on detecting the malicious pattern - it constructs and validates the final path safely.

// 04 How to test & prevent

Testing: at every input that could reach a file path - filename parameters, download and export features, template and language selectors, image loaders - submit traversal payloads and their encoded variants, and check whether the app returns a file it shouldn't (a known system file is the classic proof), errors in a revealing way, or behaves differently. It's manual, encoding-aware work. Prevention follows a hierarchy. Best: don't build filesystem paths from user input at all - map a user-supplied identifier to a known file via a lookup table, so the input is never a path. Where a path must be derived from input, resolve the final absolute path and confirm it stays within the intended base directory, rejecting anything that escapes - this validates the outcome, not the pattern, so encodings can't help the attacker. Add an allow-list of permitted files/types, run with least privilege (so even a successful traversal can't read sensitive files), and keep user-accessible files in a dedicated location. As always, safe path handling beats filtering. It's checked in every web app engagement, per our methodology.

// 05 Frequently asked questions

What is directory traversal?

Also called path traversal - a vulnerability that lets an attacker read files outside the intended directory by manipulating a file path built from user input. When an app uses input to construct a path (serving a download, loading a template, reading an image) without validating it, an attacker includes traversal sequences like ../ to climb the directory tree and reach arbitrary files - exposing config, credentials, source and system files. Where the app writes by path, it can also create or overwrite files.

What can an attacker read?

Anything the app's account can read: configuration files (often holding database credentials and secrets), environment/settings files, source code, private keys and certificates, and system files like /etc/passwd. Reading config and credentials is frequently the goal because it enables further compromise - e.g. using leaked DB credentials to access data directly. A single flaw can expose the secrets protecting everything else, so it's typically high, and critical when it exposes credentials or allows writing files.

How do attackers bypass defences?

URL-encoded or double-encoded traversal sequences to slip past filters; mixed and platform-specific separators; absolute paths where allowed; and abusing code that strips one instance of the sequence but not nested ones. Blocklisting the traversal sequence is unreliable given the many encodings and variations - robust prevention validates the final path safely rather than detecting the malicious pattern.

How do you prevent it?

Best: don't build filesystem paths from user input - map a supplied identifier to a known file via a lookup table. Where a path must be derived from input, resolve the final absolute path and confirm it stays within the intended base directory, rejecting escapes. Use an allow-list of permitted files/types, run with least privilege, and store user-accessible files separately. Safe path handling, not pattern filtering, is the reliable fix.

// 06 Related reading

UG

Usama Gul

Founder & Penetration Testing Lead, CyberFortify

Turns a download link into proof it reads your config and credentials — through the encoded traversal bypasses that defeat naive filters — then prescribes safe path construction, not pattern-blocking.

Serving files by name?

Any feature that builds a path from user input can be traversed to read your config and credentials. We test every one — through the encoding bypasses — and hand you the safe-path fix.

Scope a web app test → Web app testing →