PATH TRAVERSAL: APPLICATION SECURITY

WHAT IS PATH TRAVERSAL?
Path traversal, also known as directory traversal, is a vulnerability that enables a malicious actor to read arbitrary files on the server that runs the application. This includes the application code and data, credentials for back-end systems and sensitive OS files.
In some cases, the malicious actor may be able to write to arbitrary files on the server, allowing them to modify application data or behaviour and eventually take full control of the server.
Path traversal isn't limited to reading files. When an application accepts a user-supplied filename during an upload or write operation and passes it to the filesystem without validation, the malicious actor can control where the file lands on the server. This is often more severe than arbitrary read because it leads directly to code execution.
Common write-based attacks include uploading a webshell (a small script that executes attacker commands) into a directory served by the webserver, giving the attacker a persistent backdoor. Overwriting ~/.ssh/authorized_keys with the attacker's public key grants direct SSH access to the server. Planting a file in /etc/cron.d/ schedules attacker code to run on the next cron cycle, often as root.
READING FILES USING FILE TRAVERSAL
Consider a URL that leads to an image within the website i.e www.amazon.com/loadImage?filename=var/images/product1024.jpg. This site checks within the images folder if product1024.jpg exists. If the site is insecure, the malicious actor can swap out the image name with a folder that exists within the server such as /etc.
/etc (short for etcetera) contains system-wide configuration files. This directory comes as a default; the developer doesn’t create it from scratch. The malicious actor can simply traverse to the file by making a substitution. www.amazon.com/loadImage?filename=../../../etc/passwd
This will cause the application to read from the passwd file and gives the malicious actor all the information within that file system.
../ means it steps up one level in the directory structure. 3 consecutive ../ goes to the filesystem root. And from the root, it goes to /etc/passwd.
Sometimes the webserver strips directory traversal sequences before passing the input to the application. The malicious actor bypasses this by double-encoding the payload:
%252f..%252f..%252f..%252fetc%252fpasswd. The bypass works because the request passes through more than one decoding stage. The outer web layer decodes once, turning%252finto%2f, still a harmless-looking string with no visible slashes. The traversal filter runs on this intermediate string, scans for/or../, finds neither, and lets the request through. A later stage (often the application) decodes a second time, turning%2finto an actual/. By the time the path reaches the filesystem, the slashes are real, but the filter never got a chance to see them.Sometimes, the URL may require the user-supplied filename to start with the expected base folder i.e
/var/images. The malicious actor can bypass this by simply providing the expected base folder, going to the root and then traversing to the /etc/passwd file directory:filename=/var/images/../../../etc/passwdThe developer might try to protect the application by rejecting any filename that doesn't end in a picture extension (jpeg, png). The malicious actor bypasses this by appending a URL-encoded null byte before the extension:
../../../etc/passwd%00.png.The application code decodes the URL first, %00 becomes an actual null byte (0x00) inside the path string. The application-level check runs on the full string, sees .png at the end, and passes the request to the operating system. But the underlying OS filesystem calls (like open()) are written in C, and C treats 0x00 as the end of a string. When the OS reads the path, it stops at the null byte and never sees .png. It returns the contents of /etc/passwd.
HOW TO PREVENT A PATH TRAVERSAL ATTACK
The best way is to avoid passing user-supplied input into the filesystem API altogether. If you can’t avoid passing user-supplied input to the filesystem APIs, the developer can use these 2 layers of defense:
Validate the user input against a whitelist before processing it. A whitelist defines what is allowed, and rejects everything else. The developer chooses the whitelist based on what the endpoint actually needs to serve:
Whitelist of filenames: The strictest option. The endpoint knows the exact set of files it will ever serve (say, a lookup table of product image IDs). Any input that isn't in the set is rejected outright. Use this when possible; it makes traversal structurally impossible.
Whitelist of characters: Allow only alphanumerics, underscores, hyphens, and a single dot. Reject anything containing /, , .., null bytes, or percent-encoded characters. This is useful when filenames are user-generated but the format is predictable.
Whitelist of extensions: Allow only .jpg, .png, .gif, etc. This alone is not enough (see the null byte bypass above), but it pairs well with a character whitelist to keep users from requesting unintended file types.
After validation, the developer appends the input to the base directory and asks the operating system to canonicalize the resulting filepath. Canonicalization is the process of resolving a path into its single, unambiguous absolute form. The OS walks through every .., symbolic link, and redundant separator and reduces them to one final path that describes exactly where the file lives on disk. Every major language ships a platform API for this:
Path.resolve()in Python,File.getCanonicalPath()in Java,fs.realpathSync()in Node.js andfilepath.EvalSymlinks()in Go. Once the path is canonical, the developer checks that it still starts with the expected base directory. This ordering matters: comparing the raw string/var/images/../../../etc/passwdagainst/var/imageswill pass the prefix check, because the string does begin with/var/images. Only after the OS resolves the../sequences into the real target (/etc/passwd) does the escape become visible and the check reject it. Include a trailing slash on the base directory when comparing. Checking against/var/images(no slash) would accept a canonical path of/var/images_backup/secret.txt, because that string also starts with/var/images. Checking against/var/images/(with slash) closes that gap.
Windows uses \ as a path separator. Filters that strip ../ but not ..\ causes bugs on mixed environments.




