01Summary

Path traversal is a vulnerability that allows an attacker to access files or directories outside the intended restricted location by manipulating file paths with special sequences like .. (parent directory). When user input is used to construct file paths without proper validation, an attacker can escape the intended directory boundary and read, write, or delete sensitive files anywhere the application has permission to access.

02How It Happens

Applications often need to serve files or access data based on user input — for example, allowing a user to download a document by filename, or retrieve a user-uploaded image. If the application directly concatenates user-supplied input into a file path without sanitizing special directory traversal characters, an attacker can inject .. sequences to navigate up the directory tree. The application may intend to restrict access to /var/www/uploads/, but if it naively joins user input like ../../etc/passwd to that base path, the resulting path resolves outside the intended boundary. The operating system then follows the path as written, granting access to files the application should never expose.

03Real-World Impact

Successful path traversal can expose sensitive configuration files, private keys, database credentials, or source code. In write scenarios, an attacker might overwrite application files or inject malicious code. On shared hosting or multi-tenant systems, an attacker could access other users' data. The severity depends on what files the application process can reach — a web server running as root is far more dangerous than one in a sandboxed container, but both are vulnerable if the path traversal exists.

04Vulnerable & Fixed Patterns

Vulnerable pattern
import os

def serve_file(filename):
    base_dir = "/var/www/uploads"
    file_path = os.path.join(base_dir, filename)
    with open(file_path, 'r') as f:
        return f.read()

# User requests: "../../etc/passwd"
# Resulting path: /etc/passwd (outside base_dir)

Why it's vulnerable:
The code joins user input directly to the base directory without checking whether the resolved path stays within bounds. The .. sequences are processed by the OS, allowing escape from the intended directory.

Fixed pattern
import os

def serve_file(filename):
    base_dir = "/var/www/uploads"
    file_path = os.path.abspath(os.path.join(base_dir, filename))
    
    # Verify the resolved path is still under base_dir
    if not file_path.startswith(os.path.abspath(base_dir) + os.sep):
        raise ValueError("Access denied: path outside allowed directory")
    
    with open(file_path, 'r') as f:
        return f.read()
Vulnerable pattern
<?php
$base_dir = "/var/www/uploads";
$filename = $_GET['file'];
$file_path = $base_dir . "/" . $filename;

// User requests: "../../etc/passwd"
// Resulting path: /etc/passwd (outside base_dir)
readfile($file_path);
?>

Why it's vulnerable:
User input is concatenated directly into the file path. No validation prevents .. or absolute paths from escaping the intended directory.

Fixed pattern
<?php
$base_dir = "/var/www/uploads";
$filename = $_GET['file'];

// Remove any path traversal sequences
$filename = basename($filename);

// Alternatively, use realpath and verify containment
$file_path = realpath($base_dir . "/" . $filename);
$base_real = realpath($base_dir);

if ($file_path === false || strpos($file_path, $base_real) !== 0) {
    die("Access denied: invalid file path");
}

readfile($file_path);
?>

05Prevention Checklist

Use allowlisting, not blacklisting.
Instead of trying to block .., ./, and other sequences, explicitly allow only safe characters (alphanumeric, underscore, hyphen, dot) in filenames.
Resolve and verify paths.
Use realpath() (PHP) or os.path.abspath() (Python) to resolve the final path, then confirm it starts with the intended base directory.
Use basename() for filenames.
If you only need the filename component (not subdirectories), basename() strips any directory traversal attempts.
Avoid user input in file paths when possible.
Use a database or mapping table to associate user-friendly identifiers with safe internal filenames.
Run with minimal privileges.
Ensure the application process has permission only to access files it legitimately needs; this limits damage if traversal succeeds.
Log and monitor file access.
Unexpected attempts to access files outside the intended directory may indicate an attack in progress.

06Signs You May Already Be Affected

Check your application logs for requests containing .., ./, or encoded variants (%2e%2e, ..%2f). Review file access logs for unexpected reads of sensitive files like configuration files, private keys, or system files. If you find evidence of such requests, investigate whether they succeeded and what data may have been exposed.

07Related Recent Vulnerabilities