← Back to sandbox
Security — File Handling Intermediate 5 possible tests

Path Traversal

A file download endpoint that accepts a ?file= parameter with no path sanitization. Find the inputs that escape the base directory — including the URL-encoded and null-byte variants that bypass simple string checks.

What is Path Traversal?

Path traversal (directory traversal) lets an attacker access files outside the intended directory by injecting sequences like ../../ into a filename parameter. The server constructs a file path by joining user input to a base directory — without validation, the traversal sequences walk up the directory tree. URL-encoded variants (%2e%2e%2f) and null bytes (%00) bypass naive string checks.

What is hidden here

True Positivereport.txt — legitimate file served from the allowed directory
Bug Found../../settings.py — Django settings file returned with credentials exposed
Bug Found%2e%2e%2f%2e%2e%2fsettings.py — URL-encoded dots bypass a naive ../ string check
Bug Found../../../etc/passwd%00.jpg — null byte truncates extension, OS reads /etc/passwd
True PositiveSame traversal payloads on the sanitized endpoint are blocked by os.path.basename()

Endpoint A — Unsafe Download

This endpoint joins the filename directly to /var/www/uploads/ with no sanitization. Enter a filename or use a quick-test button.

✗ No path sanitization
Quick tests
/qa-sandbox/path-traversal/download/?file=
📄

    

Endpoint B — Sanitized Download

This endpoint applies os.path.basename() before constructing the path, stripping all directory components. Try the same payloads — none should escape the base directory.

✓ Sanitized with os.path.basename()
Quick tests
/qa-sandbox/path-traversal/safe-download/?file=
🔒
(no file contents — traversal blocked)

  • Enter report.txt on Endpoint A — legitimate file served from the allowed directory (true positive)
  • Enter ../../settings.py on Endpoint A — traversal escapes the base dir and returns the Django settings file with database credentials (bug found)
  • Enter %2e%2e%2f%2e%2e%2fsettings.py on Endpoint A — URL-encoded dots decode to ../../ before the path is joined; a check for literal ../ would miss this (bug found)
  • Enter ../../../etc/passwd%00.jpg on Endpoint A — the null byte (%00) terminates the string at the OS level; the .jpg extension check is bypassed and /etc/passwd is read (bug found)
  • Try all payloads on Endpoint B — os.path.basename() strips every directory component regardless of encoding or null bytes (true positive)