Skip to main content
CriticalProtected by PowerWAF

Directory Traversal Attack

CategoryFile & PathOWASPA01:2021 – Broken Access ControlFirst seen1999Read time9 minVerified2026-03-12
DEFINITION

A directory traversal attack exploits insufficient validation of user-supplied file paths to break out of the intended directory and access arbitrary locations on the server's file system. By injecting relative path sequences such as ../ (dot-dot-slash), encoded variants, or absolute paths, the attacker reads confidential files, discovers the application's internal structure, and β€” when combined with write primitives β€” achieves remote code execution.

How Directory Traversal Attack Works

Every web application confines its file operations to a designated root directory β€” the document root for static assets, an upload folder for user content, or a template directory for views. Directory traversal breaks this confinement. When the application builds a file system path using unsanitized user input, the attacker injects sequences that climb the directory tree until reaching the system root, then descends into any target directory. The attack surface is enormous: any parameter, header, cookie, or multipart field that ultimately feeds into a file system API is a potential entry point.

1

Map the attack surface

The attacker identifies every input that influences file system operations: URL path segments (/static/../../etc/passwd), query parameters (?file=report.pdf), POST body fields, multipart filenames, Cookie values, and HTTP headers (Content-Disposition, X-Forwarded-File). Automated scanners like DirBuster, ffuf, and Burp Intruder systematically probe these entry points. Error messages are invaluable β€” a 'file not found' exception revealing /var/www/app/pages/../../test confirms that the input reaches the file system and the traversal is interpreted.

2

Determine the traversal depth

The attacker calculates how many ../ sequences are needed to reach the file system root from the application's base directory. A common technique is to request increasingly deep traversal sequences (../, ../../, ../../../, etc.) against a file known to exist at the root β€” /etc/passwd on Linux or C:\Windows\win.ini on Windows. Once the file is returned, the depth is established. Over-traversing (using more ../ than needed) is harmless: the OS simply stays at the root.

3

Bypass input filters and WAF rules

Modern applications and WAFs detect basic ../ sequences, so attackers employ an arsenal of evasion techniques: URL encoding (%2e%2e%2f), double URL encoding (%252e%252e%252f), UTF-8 overlong encoding (..%c0%af), mixed OS separators (..\../ on Windows IIS), path normalization tricks (....// where stripping ../ once leaves ../), null byte injection (%00 to truncate appended extensions on legacy runtimes), and Unicode normalization exploits (..%u2216 using fullwidth characters). Each technique targets a different layer in the parsing stack β€” the web server, the framework, or the language runtime.

4

Extract high-value targets

With a working traversal payload, the attacker systematically extracts files in a prioritized order: (1) /etc/passwd to enumerate system users; (2) application configuration files (.env, config.php, application.yml, appsettings.json) containing database credentials, API keys, and encryption secrets; (3) /etc/shadow (if running as root) for password hashes; (4) SSH private keys (~/.ssh/id_rsa); (5) application source code to audit for further vulnerabilities; (6) cloud metadata (AWS /proc/self/environ, /var/run/secrets/kubernetes.io for K8s tokens); (7) log files containing session tokens and user data.

5

Escalate to code execution

When the traversal extends to write operations (log injection, file upload with path manipulation, or template overwriting), the attacker achieves code execution: overwriting a server-side template with malicious code, writing a PHP web shell into the document root, injecting executable content into a cron job file, or modifying .bashrc/.profile for the web server user. Even read-only traversal can lead to full compromise when extracted credentials (database passwords, API tokens, SSH keys) provide lateral movement pathways into other systems.

Real-World Examples

2021

Apache HTTP Server 2.4.49/2.4.50 (CVE-2021-41773 & CVE-2021-42013)

A critical directory traversal flaw in Apache HTTP Server allowed unauthenticated attackers to map URLs to files outside the expected document root using URL-encoded dot-dot sequences (.%2e). The initial fix in 2.4.50 was immediately bypassed via double encoding (%%32%65), leading to CVE-2021-42013. When combined with mod_cgi, the vulnerability enabled remote code execution. Threat actors began mass exploitation within 24 hours, targeting an estimated 112,000 exposed servers. CISA added it to the Known Exploited Vulnerabilities catalog.

2019

Fortinet FortiOS SSL VPN (CVE-2018-13379)

A directory traversal in the Fortinet SSL VPN web portal allowed unauthenticated attackers to read arbitrary system files by crafting HTTP requests with specially formed path segments. Attackers extracted VPN session tokens to hijack authenticated sessions. In November 2020, a threat actor published a list of nearly 50,000 vulnerable Fortinet VPN IP addresses, and in September 2021, credentials for 87,000 devices were leaked on a dark web forum. The vulnerability was exploited by APT groups including APT29 (Cozy Bear) and was cited in a joint FBI/CISA advisory.

2019

Citrix ADC/Gateway (CVE-2019-19781) β€” 'Shitrix'

A directory traversal vulnerability in Citrix Application Delivery Controller and Gateway allowed unauthenticated remote code execution. Attackers traversed to a writable template directory and planted a malicious XML file that was then rendered by the Perl-based template engine, achieving command execution. Over 80,000 organizations in 158 countries were vulnerable. Exploitation began on January 10, 2020 β€” within weeks of PoC release β€” and was used to deploy ransomware (including REvil and DoppelPaymer) against healthcare, government, and financial institutions.

Impact & Risk Assessment

Directory traversal is classified as Critical because it collapses the most fundamental security boundary in web applications: file system isolation. A successful attack yields immediate access to configuration files containing database credentials, API secrets, and encryption keys. On cloud-hosted workloads, it exposes instance metadata endpoints and service account tokens, enabling full cloud account takeover. When write access is achievable, the path to remote code execution is direct. Historical data from vulnerability disclosure programs shows that directory traversal consistently ranks among the top 5 most frequently reported vulnerability classes in bug bounty programs. The attack requires no authentication, no special tooling, and often bypasses perimeter defenses β€” making it accessible to low-skill attackers while remaining devastating in impact.

How to Detect Directory Traversal Attack

Deploy multi-layered detection: (1) WAF rules matching ../ and its encoded variants (%2e%2e, %252e%252e, %c0%ae%c0%ae, ....//), null bytes (%00), and references to known sensitive paths (/etc/passwd, /etc/shadow, /proc/self, win.ini, web.config); (2) Application-level logging of all file system operations with the resolved canonical path, alerting when any resolved path falls outside the expected base directory; (3) Runtime Application Self-Protection (RASP) intercepting file I/O system calls and blocking out-of-bounds access in real time; (4) Network-level IDS/IPS signatures for traversal patterns in HTTP traffic; (5) File integrity monitoring (AIDE, OSSEC) on critical system files to detect unauthorized reads via access-time changes. Correlate traversal attempts with the requesting IP's threat intelligence score to prioritize incident response.

How to Prevent Directory Traversal Attack

Adopt a defense-in-depth strategy: (1) Never construct file paths from user input β€” use an allowlist or indirect reference map (user submits an ID, server maps it to a pre-defined path); (2) If dynamic paths are unavoidable, resolve the canonical path (realpath() in C/PHP, Path.GetFullPath() in .NET, os.path.realpath() in Python, path.resolve() in Node.js) and verify it starts with the expected base directory using a strict prefix check; (3) Reject any input containing path separators (/, \), traversal sequences, null bytes, or URL-encoded variants β€” do this after decoding; (4) Use OS-level isolation: chroot jails, Linux namespaces, Docker containers with read-only root filesystems, or AppArmor/SELinux profiles restricting the process's file access; (5) Apply the principle of least privilege β€” the web server process should own and access only its document root; (6) Deploy a WAF with comprehensive traversal signatures, including encoded and Unicode variants; (7) On Windows IIS, disable short filename (8.3) generation to prevent PROGRA~1-style traversal.

Code Examples

Vulnerable: Express.js static file handler
const express = require('express');
const path = require('path');
const fs = require('fs');

const app = express();

// VULNERABLE: user input directly concatenated into file path
app.get('/files/:name', (req, res) => {
const filePath = path.join(__dirname, 'uploads', req.params.name);
// No validation β€” attacker uses: /files/..%2f..%2f..%2fetc%2fpasswd
fs.readFile(filePath, (err, data) => {
if (err) return res.status(404).send('Not found');
res.send(data);
});
});

// Attacker requests:
// GET /files/....//....//....//etc/passwd
// GET /files/%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd
// GET /files/..%252f..%252f..%252fetc%252fpasswd (double encoding)
Secure: Canonical path validation with allowlist
const express = require('express');
const path = require('path');
const fs = require('fs');

const app = express();
const UPLOAD_DIR = path.resolve(__dirname, 'uploads');

app.get('/files/:name', (req, res) => {
const fileName = req.params.name;

// 1. Reject any path separators or traversal sequences
if (/[\/\\]/.test(fileName) || fileName.includes('..')) {
return res.status(400).json({ error: 'Invalid filename' });
}

// 2. Resolve the canonical (real) path
const resolved = path.resolve(UPLOAD_DIR, fileName);

// 3. Strict prefix check β€” must be inside UPLOAD_DIR
if (!resolved.startsWith(UPLOAD_DIR + path.sep)) {
return res.status(403).json({ error: 'Access denied' });
}

// 4. Verify file exists and is a regular file (not symlink to outside)
fs.lstat(resolved, (err, stats) => {
if (err || !stats.isFile()) {
return res.status(404).json({ error: 'Not found' });
}
// 5. Check the real path of symlinks too
const real = fs.realpathSync(resolved);
if (!real.startsWith(UPLOAD_DIR + path.sep)) {
return res.status(403).json({ error: 'Access denied' });
}
res.sendFile(real);
});
});
Secure: Go http.FileServer with jail
package main

import (
"net/http"
"os"
"path/filepath"
"strings"
)

func safeFileHandler(baseDir string) http.HandlerFunc {
absBase, _ := filepath.Abs(baseDir)

return func(w http.ResponseWriter, r *http.Request) {
// Clean the requested path
reqPath := filepath.Clean(r.URL.Path)

// Resolve the full path
fullPath := filepath.Join(absBase, reqPath)
absPath, err := filepath.Abs(fullPath)
if err != nil {
http.Error(w, "Invalid path", http.StatusBadRequest)
return
}

// Verify the resolved path is within the base directory
if !strings.HasPrefix(absPath, absBase+string(os.PathSeparator)) {
http.Error(w, "Forbidden", http.StatusForbidden)
return
}

// Resolve symlinks and re-check
realPath, err := filepath.EvalSymlinks(absPath)
if err != nil {
http.Error(w, "Not found", http.StatusNotFound)
return
}
if !strings.HasPrefix(realPath, absBase+string(os.PathSeparator)) {
http.Error(w, "Forbidden", http.StatusForbidden)
return
}

http.ServeFile(w, r, realPath)
}
}

func main() {
http.HandleFunc("/files/", safeFileHandler("./uploads"))
http.ListenAndServe(":8080", nil)
}

Frequently Asked Questions

The terms are largely interchangeable and refer to the same class of vulnerability. When a distinction is made, 'directory traversal' emphasizes navigating the directory tree structure (the ../ sequences), while 'path traversal' is the broader term encompassing any manipulation of file paths, including absolute path injection (/etc/passwd without ../) and protocol-level path abuse. OWASP and CWE-22 treat them as synonyms. In practice, you should test for both relative traversal (../) and absolute path injection.
On both Linux and Windows, attempting to traverse above the file system root (/) is a no-op β€” the OS simply stays at the root. This means an attacker doesn't need to know the exact depth of the application directory: using 15 or 20 ../ sequences guarantees reaching the root regardless of the application's actual location. This is why depth-based defenses (counting ../ occurrences) are unreliable β€” the attacker can always add more.
Absolutely. REST APIs that serve files or accept file path parameters, GraphQL resolvers that load schemas or templates from disk, and microservices that read configuration files based on request data are all vulnerable. Container orchestration amplifies the risk: a traversal in a containerized service can access mounted secrets (/var/run/secrets/), service account tokens, and environment files that provide lateral movement across the cluster.
No. HTTPS encrypts the transport layer between client and server, preventing eavesdropping and tampering in transit. Directory traversal is an application-layer vulnerability β€” the malicious payload is inside the encrypted HTTP request. HTTPS provides zero protection against it. The traversal sequences reach the application's file handling code regardless of whether the connection is encrypted.
A WAF inspects incoming HTTP requests for traversal signatures before they reach the application. This includes literal ../ patterns, URL-encoded variants (%2e%2e%2f, %252e%252e%252f), Unicode and overlong UTF-8 encodings, null byte injection, and requests targeting known sensitive file paths. PowerWAF's traversal detection engine applies multi-pass decoding (URL, HTML entity, Unicode normalization) to defeat encoding-based evasion, covering over 60 distinct traversal patterns across Linux, Windows, and mixed-platform environments.

PowerWAF automatically blocks Directory Traversal Attack at the edge.

Deploy in minutes. No code changes required. Free plan available.

Free plan spots are limited Β· No credit card required