Find every place user input becomes part of a file path. Then ask whether the code maps input to an ID instead, fixes the base directory, validates against known good values, and normalizes before touching the file system. Sequences like dot dot slash let input climb out of the intended folder.
What path traversal is
OWASP describes path traversal as accessing files and directories outside the web root by manipulating file-referencing input. It can expose source code, configuration files and critical system files, though operating system access controls still apply.
Common techniques it lists include dot dot slash sequences, absolute paths that skip the intended directory, a cookie value used in an include call, and requesting a script file directly to see its source.
Encodings that get past naive checks
| Variant | Example from OWASP |
|---|---|
| URL encoding | %2e%2e%2f for ../ |
| Mixed encoding | ..%2f and %2e%2e/ |
| Double encoding | %252e%252e%255c |
| Overlong UTF-8 | ..%c0%af |
| Null byte | secret.doc%00.pdf |
| Windows quirks | Both / and \ work as separators |
A check that only searches for the literal string dot dot slash misses all of these. That is why OWASP advises validating against known good values and not trying to sanitize bad input.
What to look for in the diff
- Search for file open, read, send file and include calls. Trace each argument backwards.
- Look for string joins between a base directory and a request value.
- Check for blocklist style fixes, such as replacing dot dot slash with an empty string. Nested sequences can rebuild the original.
- Check where the base directory is defined and whether it is fixed in code.
- Check that sensitive configuration lives outside the web root.
# red flag
return send_file("/srv/reports/" + request.args["name"])
# safer: input selects from a known set
REPORTS = {"daily": "daily.pdf", "weekly": "weekly.pdf"}
name = REPORTS.get(request.args.get("name"))
if name is None:
abort(404)
return send_file("/srv/reports/" + name)
The prevention list
OWASP's recommendations, in review terms: avoid user input in file system calls where possible; map input to indexes or IDs instead of file names; do not let users control the entire path, and fix the base directory in code; validate against a list of known good values; if user input must be used, normalize it before passing it to file APIs; restrict access with chroot jails or code access policies; and keep sensitive files outside the web root.
When normalization is the chosen approach, the usual check is to resolve the final path and confirm it still starts with the intended base directory. Do the check after resolving, not before.
Archives are a related case
Unpacking an archive writes files whose names come from the archive. Check that extraction code validates each entry's destination in the same way.
Where Safeguard fits
Safeguard scans dependencies and builds SBOMs, which covers libraries with known traversal flaws. Try the free scan at gold.safeguard.sh/scan.
Quick check
Is removing dot dot slash from input enough?
No. Encodings and nested sequences can get past it. Validate against known good values instead.
How should a user pick a file?
Map their choice to an ID or index that your code resolves to a fixed file, as OWASP suggests.
Sources
Last reviewed: 19 October 2026.