EMZETT.
Login

Path traversal and insecure file uploads: detecting and preventing

In short: In path traversal an attacker smuggles path parts such as ../ into a file request to read files outside the permitted folder; insecure uploads allow harmful files to be introduced.

In more detail: Web applications often read or store files based on user input (/download?file=report.pdf). If the input is built into a path unchecked, file=../../etc/passwd can reveal system files. This article explains understanding and defence for your own applications.

In Depth

Path traversal (directory traversal)

../ climbs up the directory tree. Example: base /var/www/files/ + input ../../../etc/passwd → /etc/passwd. Variants: URL-encoded (%2e%2e%2f), double-encoded, backslashes (..\) on Windows, absolute paths, null bytes, symlinks. Consequences: reading configurations, keys, source code, database credentials; with write access even code execution. Typical places: download/image/template endpoints, ZIP extraction (Zip Slip: entry ../../evil), log viewers, template selection.

Defence

  • Do not use file names from user input, but IDs (database entry → stored path) or an allowlist.
  • Normalise and check the path: build the resolved path (Path.resolve(), realpath) and make sure it starts with the base folder.
base = Path("/var/www/files").resolve()
target = (base / user_input).resolve()
if not target.is_relative_to(base):
    abort(400)
  • Minimise rights (process may only read its folder), chroot/container, read-only file systems.
  • Use frameworks (send_from_directory), check ZIP entries.
  • Error messages without paths.

Insecure file uploads

Risks: executable files (PHP/JSP web shell) in the web root, overwriting other files, huge files (DoS), image/document formats with malicious code (SVG with script → XSS, PDF/Office macros, polyglot files), wrong types (extension ≠ content), path in the file name. Protection:

  • Check type (magic bytes/content, not only extension/Content-Type), allowlist of formats.
  • Rename (random ID), original name only as metadata.
  • Store outside the web root or deliver via object storage (S3), no execution (noexec, header X-Content-Type-Options: nosniff, Content-Disposition: attachment).
  • Size limit, rate limiting, virus scan, re-encode images (removes metadata/payload).
  • Sanitise or forbid SVG, deliver on a separate domain (separate cookies/origin).

Testing and learning

  • Test your own application with ../ inputs (unit tests), static analysis (Semgrep/CodeQL), dependency updates (unpacking libraries).
  • Practise legally: OWASP Juice Shop, DVWA, WebGoat, PortSwigger Academy, TryHackMe (your own lab!).
  • Legal: never test third-party systems without permission (§ 202a–c StGB, see hacking law).
  • Classification: OWASP Top 10 (broken access control, injection, security misconfiguration).
  • Report findings via responsible disclosure.

See also: OWASP Top 10, SQL injection, Responsible disclosure