🌐 This article is also available in: Deutsch

Directory traversal: The underestimated nightmare in web security

Directory traversal: The underestimated nightmare in web security
Directory Traversal

Imagine someone rings your doorbell and you let them into your hallway. So far, so good – but suddenly they start sneaking through all the rooms, rummaging through your drawers and even reading your private documents. This is exactly what happens digitally when a web application is not secured against directory traversal.

In this attack, hackers use simple tricks such as ../ to move outside the intended directory and gain access to confidential files – from inconspicuous log files to secret configuration files. Sounds simple? It is. And that’s exactly why this vulnerability is so dangerous.

In this article, we’ll look at how directory traversal works, what examples there are in practice, why this security vulnerability is often underestimated – and how you can secure your applications so that no attacker can rummage through your “digital drawers.”

What is Directory Traversal?

Directory traversal is a security vulnerability that allows an attacker to use manipulated path specifications to access files and directories outside the intended scope of a web server (or file system). This often involves someone using ../ (or ..\ on Windows) in a URL or parameters to climb “up” the directory tree – i.e., to climb out of the “web root” or a protected directory in order to access sensitive files.

A few synonyms and related terms:

  • Path traversal
  • File path traversal
  • Directory climbing/backtracking
  • CWE-22 (Common Weakness Enumeration for Improper Limitation of a Pathname to a Restricted Directory)

Why is that dangerous?

Because such gaps often lead to really nasty consequences:

  • Reading confidential files, e.g., /etc/passwd, configuration files, private keys, log files, etc.
  • In some cases, even writing or modifying them (e.g., during archive extraction, symbolic links, etc.)
  • Possible remote code execution if an attacker can take control by reading/modifying files.
  • Data loss, loss of image, legal problems (data protection violations), and, of course, loss of trust.

Types & Variants

Bevor wir in Beispiele gehen: Hier sind ein paar wichtige Varianten von Directory Traversal:

Variant
Description
Relative Path Traversal
Use ../ or ..\ from an existing path to navigate upwards.
Absolute Path Traversal
Specify a complete path such as /etc/passwd or C:\Windows\system32\drivers\etc\hosts.
Encoded / URL-encoded traversal
Paths or the ../ sequence are URL-encoded, e.g. %2e%2e%2f etc., to bypass simple filters.
Unicode / Non-standard encoding
Obfuscation through Unicode expressions or multiple encodings to trick filters.
Archive/ZIP traversal
When unpacking archive files that contain referenced directories outside of permitted areas (e.g., through symbolic links or path specifications in the ZIP file).

Truly dangerous examples from real life

To illustrate this in practice, here are a few real-life examples:

  • The WordPress plugin “SEO Tools” was vulnerable to relative paths being used via a file parameter to read Windows system files such as win.ini.
  • The Rank Math SEO plugin recently had a path traversal vulnerability: CVE-2023-23888.
  • The Squirrly SEO plugin (version < 6.1.5) had a directory traversal vulnerability via the sq_size parameter.

These examples show that even large, widely used plugins are not immune. And often the problem is simply insufficient input validation or overly lax file path processing.

How can you recognize directory traversal?

As a security professional or developer, you should check for the following signs in code/requests:

  • Parameters that are used directly in file operations (e.g., include(…), open(…), readfile(…)) without prior validation or whitelisting.
  • “../”, “..\”, double encoding (%2e, %2f, etc.), Unicode workarounds in parameters.
  • Missing or insufficient restrictions to ensure that paths always remain under a specific base directory.
  • Error messages or stack traces that allow conclusions to be drawn about the file system.
  • Access to files that should not be public (e.g., .env, config.php, etc.).
  • Log files that show unusual paths or multiple “../”.

Directory Traversal finden - Step by Step

Note: Only perform these steps in an authorized test environment or with written permission. The examples use a harmless test file called lab-proof.txt, which you can create in Webroot.

1) Preparation (Lab)

  • In your test web app, create the file lab-proof.txt with the content lab-test-2025 in the uploads/ directory.
  • Enable server access logs and error logs.
  • Ensure that the web server contains sensitive files elsewhere (e.g., /etc/), but that these cannot be read — we will not request them.
  • Start a proxy (e.g., Burp, ZAP) to record the requests.

Example (description only):
/var/www/html/uploads/lab-proof.txt -> Content: lab-test-2025

Tip: There are ready-made labs you can use to train your skills, e.g., Hack the Box (HTB).

2) Recon - Find endpoints & parameters

Search the web app for clues as to which URLs/parameters accept file names. Typical candidates: download, file, img, path, document, view.

Example URL (found on a page or in an API description):
https://test.local/download?file=…

Note the request type (GET/POST), parameter name, and content type.

Check controlled access

Goal: Prove that the parameter actually delivers files – using the controlled test file.

Example Request (GET)

GET /download?file=uploads/lab-proof.txt HTTP/1.1
Host: test.local
User-Agent: curl/8.2.1
Accept: */*

Equivalent with curl:

curl -i "https://test.local/download?file=uploads/lab-proof.txt"

Example Response - successful access

HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 13
Server: TestServer/1.0
lab-test-2025

Interpretation:

Status 200 OK + Body contains lab-test-2025 → the file parameter controls file access.

If you see this behavior, you have a secure, reproducible basis for further testing.

3) Test variants - conceptually & non-destructively

Now systematically run through variations to obtain indications of traversal vulnerability. Important: Only use harmless path variations here (e.g., to the same lab-proof.txt).

Objective: Check whether the application allows path manipulation.

Example 1 — relative path variant (conceptual)

GET /download?file=uploads/../uploads/lab-proof.txt HTTP/1.1
Host: test.local

Possible response (if normalization is missing)

HTTP/1.1 200 OK
Content-Length: 13
lab-test-2025

Meaning: The application did not sufficiently normalize or check the .. sequence — it follows the path and reads the file anyway.

4) Systematic hypothesis testing (structured approach)

Work with clear hypotheses and document results.

Example hypothesis:
file is passed to readFile() unfiltered, without canonicalization.”

Test steps:

  1. Baseline: /download?file=uploads/lab-proof.txt → 200 + lab-test-2025 (success).
  2. Variation A: /download?file=uploads/../uploads/lab-proof.txt → 200? If yes, hypothesis supported.
  3. Variation B: URL-encoded form of the variation → check behavior.
  4. Check logs: Will ../ appear in the log? What error messages?

Log: Request, response (status, headers, body snippet), log lines, timestamp.

5) Proof-of-Concept (PoC) - secure & minimal

Your PoC should demonstrate that the vulnerability exists without reading productive files.

Example PoC (filled report section)

  • Endpoint: GET /download?file=…
  • Parameter: file
  • Test file: uploads/lab-proof.txt (content: lab-test-2025)
  • Reproduction steps (conceptual):
    1. Create lab-proof.txt in uploads/.
    2. Request: GET /download?file=uploads/lab-proof.txt → 200 + lab-test-2025.
    3. Request: GET /download?file=uploads/../uploads/lab-proof.txt → also 200 + lab-test-2025.
  • Evidence: Copies of both responses (status + body excerpt) + corresponding log line.
  • Risk assessment: Medium to high impact — an attacker could potentially use path manipulation to read outside of intended areas. (No tests performed on production files.)

6) Recommendations for reliable testing / No-go rules

  • Do not test on productive systems without explicit permission.
  • Do not attempt to read sensitive or system files.
  • Do not perform write/delete operations.
  • Limit request rates so as not to overload systems.
  • Document each step so that you can report back later in a comprehensible manner.

Protective measures / Countermeasures

Here are my top tips on how to prevent directory traversal – based on several decades of experience:

  1. Input validation & whitelisting
  2. Canonicalization (path normalization)
  3. Avoid passing user input directly to file system APIs
  4. Restrictive file system permissions
  5. Logging & Monitoring
  6. Updates & patches
  7. Testing / Penetration Tests / Code Reviews

Code Examples

To make everything a little more tangible, here are two simple code examples – one insecure, one secure.

Insecure example (PHP)

# Pseudocode – vulnerable version (no sanitization)
if url_parameter("file") exists:
    path = url_parameter("file")
    load_file("/var/www/html/uploads/" + path)  # ← no protection!

If someone uses ?file=../../etc/passwd, the file /etc/passwd may be included.

Example secure

# Pseudocode – secure version with whitelist validation
if url_parameter("file") exists:
    filename = get_basename(url_parameter("file"))  # strips ../ etc.
    allowed = ["image1.jpg", "image2.png", "report.pdf"]
    if filename in allowed:
        load_file("/var/www/html/uploads/" + filename)
    else:
        return_error(400, "Invalid file.")

Plus: Instead of include, you could use realpath() or canonicalize() functions to check whether the path remains within the permitted directory.

Additional tools and resources

  • CWE-22 – as a reference for this type of vulnerability.
  • Security scanners such as OWASP ZAP, Burp Suite, Acunetix – they have rules for path/directory traversal.
  • CVE databases, patch lists for many plugins (e.g., WordPress plugins such as Rank Math, Squirrly) as examples of what was currently vulnerable.

Common mistakes & bypasses

Experience shows that even with good measures in place, it is possible to fall into traps. Here are some typical mistakes and bypass techniques:

  • Wildcards or path specifications that are not sufficiently filtered.
  • Multiple encoding (e.g., %2e%2e%2f, Unicode encoding) bypasses simple filters.
  • Zero-byte injection (formerly a common trick) – relevant depending on language/platform.
  • Symbolic links within permitted directories that point outside.
  • Incorrect configuration of base directories or root paths.
  • Logical errors: The path is checked before concatenation, but not again after encoding/normalization.

Conclusion

At first glance, directory traversal may seem like a “simple trick” – a few dots and the world is your oyster. In reality, the problem runs much deeper: it is an architecture and design flaw combined with insufficient input hygiene and lax permissions. The greatest risks arise when developers build file paths directly from user input and administrators configure file systems in such a way that sensitive files are unnecessarily accessible.

What you should take away: Avoid blacklists, rely on whitelists and canonicalization, practice restrictive rights management, and monitor path accesses that are suspected of being anomalous. For operators, this means patching, checking, and evaluating logs. For developers, this means never blindly opening files from user input – instead, use references, IDs, or strict mapping.

And for everyone: Practice regularly in the lab, perform controlled penetration tests, and always act in a legally and ethically correct manner. Directory traversal is a low-tech vulnerability with high impact – don’t ignore it.