File Upload Vulnerabilities: The Complete Practical Guide

File Upload Path Traversal via Filename

Using directory traversal in an upload filename to escape the upload directory, write into the web root, and overwrite config or cron files.

Published

Most upload bugs are about what is in the file. This one is about where it goes. If the app builds the save path from the filename you supply, you can put directory traversal in that name and write your file somewhere it was never meant to land, like the web root for execution, or straight over a sensitive file.

Putting traversal in the stored filename

Apps often save an upload by joining a fixed directory with your filename. When the filename is not sanitized, ../ sequences in it climb out of that directory:

filename="../../../../var/www/html/shell.php"
filename="../../config/app.php"

The server intended to write into its uploads folder, but your name steers the write up and over to the path you chose. The upload feature becomes an arbitrary file write.

Writing into the web root

The highest-value destination is usually a directory the server executes. If uploads are normally stored outside the web root (a common, otherwise-good practice), traversal puts your file back inside it:

filename="../../../var/www/html/uploads/shell.phtml"

Land an executable file in the web root and you are back to a web shell, even though the app tried to keep uploads away from executable paths.

Overwriting existing files

Traversal is not only about placing new files, it is about replacing important ones. Point the write at something the server trusts:

  • A configuration file, to change app behavior or credentials.
  • A cron file or scheduled task, to get code run on a timer.
  • An SSH authorized_keys file, to add your key.
  • An application source file, to backdoor it.

Overwrites turn an upload into persistence or privilege, not just a one-off shell.

Encoded traversal

If the app strips or blocks a literal ../, encode it so the traversal survives until the server decodes it:

filename="..%2f..%2f..%2fshell.php"        (URL-encoded slashes)
filename="..%252f..%252fshell.php"         (double-encoded)
filename="....//....//shell.php"           (beats a single-pass ../ strip)

The ....// form is worth remembering: a filter that removes one ../ from ....// leaves ../ behind, so a single cleanup pass hands you the traversal it tried to remove.

The broader technique

Filename traversal is one instance of directory traversal, the same class of bug that lets an attacker read or write files outside an intended directory anywhere user input becomes a path. The full ladder of traversal encodings and sanitizer bypasses applies here too, so when a simple ../ is filtered, work through the encoded and doubled variants methodically.

Defensively, the fix is to discard the user's filename entirely and generate your own, which is covered in preventing upload flaws. Practice steering an upload with its filename on a free live target.

← Back to File Upload Vulnerabilities: The Complete Practical Guide