Safeguard
Vulnerability Analysis

What is Directory Traversal

Directory traversal (CWE-22) lets attackers use ../ sequences to read or write files outside a web app's root directory. Here's how it works.

Bob
Application Security Engineer
7 min read

Directory traversal (also called path traversal) is a vulnerability class where an attacker manipulates file-path input to break out of a web application's intended directory and access files elsewhere on the server. The classic payload looks like GET /download?file=../../../../etc/passwd, where each ../ walks one level up the directory tree until the request lands outside the web root. It's tracked as CWE-22 ("Improper Limitation of a Pathname to a Restricted Directory"), and it has been exploitable in production software since at least CVE-2000-0884, an IIS 5.0 Unicode-encoding bypass disclosed in October 2000. More than two decades later, the same root cause — an application trusting user-supplied input to build a filesystem path — still produces critical CVEs, including a 9.8-severity Apache HTTP Server flaw in 2021 and a 9.8-severity PHP-CGI flaw in 2024. Here's how the attack works, how attackers evade filters, and what actually stops it.

What Is a Directory Traversal Attack?

A directory traversal attack occurs when an attacker supplies specially crafted input — typically containing ../ sequences, absolute paths, or encoded variants of both — to a parameter that an application uses to construct a file path, causing the application to read, write, or execute a file outside its intended directory. The most common target is arbitrary file read: an attacker requests ../../../../etc/passwd on Linux or ..\..\..\..\windows\win.ini on Windows to confirm the flaw, then pivots to configuration files, source code, SSH keys, or /proc/self/environ to harvest credentials. When the same flaw applies to a write or extract operation — for example, an image-upload handler or a ZIP/TAR extraction routine — the attacker can overwrite application code, planted web shells, or cron jobs, turning a "read" bug into remote code execution. OWASP's Web Security Testing Guide (WSTG-ATHZ-01) lists path traversal as one of the first authorization checks to run against any endpoint that accepts a filename, path, or file ID as a parameter.

How Do Attackers Bypass Directory Traversal Filters?

Attackers bypass traversal filters by encoding the same ../ sequence in a form the filter doesn't recognize but the underlying OS or web server still normalizes correctly. Common techniques include single URL encoding (%2e%2e%2f for ../), double encoding (%252e%252e%252f), Unicode/overlong UTF-8 encoding (%c0%ae%c0%ae%c0%af), mixed slash types (..\/ or ....//), null-byte truncation (file.php%00.jpg, effective against older PHP versions that stopped string processing at a null byte), and absolute-path injection that skips traversal sequences entirely (/etc/passwd supplied directly to a naive concatenation like basePath + userInput). CVE-2000-0884 is the textbook case: IIS 5.0 decoded %c1%1c and similar overlong UTF-8 sequences into . and / after its traversal filter had already run, letting attackers read any file on the volume. The same "decode-after-filter" logic error resurfaced in CVE-2021-41773 twenty-one years later, when Apache HTTP Server 2.4.49 failed to block path traversal for URLs containing dot-segment-encoded characters, and in unpatched configurations allowed direct RCE via CGI scripts.

Which Real-World CVEs Illustrate the Impact of Path Traversal?

Four CVEs show how a single traversal flaw escalates from file disclosure to full compromise. CVE-2021-41773, disclosed October 5, 2021 and affecting Apache HTTP Server 2.4.49, let attackers map URLs to files outside the configured document root; because CGI and mod_userdir setups exposed script execution paths, the bug chained into remote code execution, and Apache's own security team observed exploitation attempts within 24 hours of disclosure. Apache's first patch was incomplete, requiring a second CVE (CVE-2021-42013) and a follow-up release, 2.4.51, within days. CVE-2024-4577, disclosed May 7, 2024 by DEVCORE and rated CVSS 9.8, is a Windows-specific PHP CGI-mode argument-injection bug rooted in path traversal handling of Windows' "Best-Fit" character encoding; Akamai and other researchers reported active exploitation delivering Cobalt Strike and cryptominers within weeks of the advisory. CVE-2019-16278 hit Nostromo nhttpd 1.9.6, where a crafted HTTP request bypassed directory checks to achieve RCE; it was added to CISA's Known Exploited Vulnerabilities catalog. And in 2018, researchers publicly disclosed "Zip Slip," a traversal pattern in archive-extraction code affecting libraries across at least eight ecosystems (Java, JavaScript, .NET, Go, Groovy, Ruby) and found in products from Amazon, LinkedIn, Twitter, IBM, and Apache — proof that traversal bugs live in library code, not just custom endpoint handlers.

What's the Difference Between Path Traversal and Local File Inclusion?

Path traversal and local file inclusion (LFI) both escape an intended directory, but they differ in what the application does with the file once it's reached. Path traversal typically returns file contents to the attacker as static data — think a download endpoint that echoes back whatever file it opens. LFI goes further: the application executes or interprets the traversed file, most often by passing it to a template engine, an include()/require() call in PHP, or a server-side include directive. That distinction matters for severity — LFI against a PHP application combined with a way to plant attacker-controlled content (a poisoned log file, an uploaded avatar, or php://filter wrappers) frequently yields direct code execution, while plain path traversal "only" yields disclosure unless it targets a write path. Both share the same CWE-22 root cause and the same fix: never let user input select a filesystem path without validation.

How Can Development Teams Prevent Directory Traversal Vulnerabilities?

Development teams prevent directory traversal by rejecting relative path input outright and resolving every file operation against a fixed, canonicalized base directory before use. Concretely: canonicalize the requested path (realpath() in PHP, Path.GetFullPath() in .NET, os.path.realpath() in Python) and verify the result still starts with the intended base directory string — checking for ../ substrings alone is insufficient, as the encoding bypasses above demonstrate. Prefer indirect references over raw filenames: map user-facing file IDs to server-side paths through a lookup table or database record rather than accepting a path fragment directly. Run web server and application processes with a filesystem-level jail (chroot, a restricted service account, or a container with a minimal read-only mount) so that even a successful traversal has nowhere to go. For archive handling, use extraction libraries patched against Zip Slip and validate that every extracted entry's resolved path stays inside the target directory before writing. Finally, patch known-vulnerable versions fast — CVE-2021-41773 and CVE-2024-4577 both had public exploit code within a week of disclosure, and unpatched instances were still being scanned months later.

How Common Is Path Traversal Across Today's Software Supply Chain?

Path traversal remains common because it isn't confined to custom application code — it ships inside open-source dependencies that thousands of downstream projects pull in without inspecting file-handling logic. CWE-22 has appeared in MITRE's CWE Top 25 Most Dangerous Software Weaknesses list every year it has published one since 2019, and NVD has recorded traversal-related CVEs across nearly every major ecosystem: Java (Zip Slip-affected libraries), Node.js (decompress-zip, tar prior to patched versions), Go (archive/tar misuse), and PHP (dozens of CMS plugins). Because the vulnerable code is frequently a transitive dependency two or three levels deep, teams relying on manual code review or basic SCA "is this package version affected" matching routinely miss whether the vulnerable function is actually reachable from their application's entry points — which is the difference between a finding that needs triage this sprint and one that can wait.

How Safeguard Helps

Safeguard closes the gap between "a directory traversal CVE exists in a dependency" and "this CVE is actually exploitable in our application." Reachability analysis traces whether the vulnerable file-handling function in a flagged package — say, an archive extractor affected by a Zip Slip-class flaw — is actually invoked from your code paths, so security teams can deprioritize the 80%+ of traversal findings that sit in dead or unreachable code and focus remediation where it matters. Griffin AI reviews the affected function's call sites and surrounding logic to explain the exploit path in plain language, cutting triage time from hours to minutes. Continuous SBOM generation and ingest keep an accurate, current inventory of every archive, upload, and file-handling library across your services, so newly disclosed traversal CVEs like CVE-2024-4577 are matched against your stack automatically instead of during the next manual audit. When a fix is available, Safeguard opens an auto-fix PR with the patched dependency version pinned, so the vulnerable path-normalization code is replaced before an attacker finds it.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.