A path-traversal attack uses ../ sequences to escape an intended directory and reach files like /etc/passwd. Encoding makes it worse — ..%2F and double-encoded %252e slip past naive filters. The reliable defence is to canonicalize first, then validate.
If your app builds a file path from user input, an attacker supplies ../ to climb out of the intended folder:
// VULNERABLE — user controls the filename
app.get('/download', (req, res) => {
const file = req.query.name; // "../../etc/passwd"
res.sendFile('/var/app/files/' + file); // escapes the folder!
});
Checking the raw string for ../ isn’t enough, because the same payload can arrive encoded — and each layer of encoding hides it from a filter that only inspects the surface:
../../etc/passwd plain
..%2F..%2Fetc%2Fpasswd slash encoded
%2e%2e%2f dots encoded too
%252e%252e%252f DOUBLE-encoded (%25 = %) — beats one decode pass
This is why the rule is canonicalize first, then validate: fully decode and normalize the path before you inspect it, so all these forms collapse to the same canonical string.
Resolve the requested path against the intended base directory, then confirm the result is still inside that directory:
const path = require('node:path');
function safeJoin(baseDir, userInput) {
// path.normalize collapses ../ and ./ ; resolve makes it absolute
const target = path.resolve(baseDir, userInput);
// reject anything that escaped the base directory
if (!target.startsWith(path.resolve(baseDir) + path.sep)) {
throw new Error('Path traversal blocked');
}
return target;
}
app.get('/download', (req, res) => {
try {
const file = safeJoin('/var/app/files', req.query.name);
res.sendFile(file);
} catch {
res.status(400).send('Invalid path');
}
});
../ survives.To see what a suspicious encoded path actually contains, decode it (recursively, to strip every layer) with the URL decoder. The decode-then-validate guide covers this evasion pattern in depth.
Written and maintained by the urlencodedecode.com team. Every technical claim on this page is verified against primary sources — the RFCs (3986, 3629, 4648, 7578), the WHATWG URL Standard, and official vendor or language documentation — rather than second-hand summaries. When a source contradicts a common assumption, we follow the source and note the discrepancy. Corrections: contactus@urlencodedecode.com.
It's when an attacker supplies ../ sequences in user input to escape an intended directory and reach files outside it, such as /etc/passwd. It happens when an application builds a file path from unvalidated user input.
Because the same payload can arrive percent-encoded (..%2F), double-encoded (%252e%252e), or with dots encoded (%2e%2e%2f), which a filter inspecting only the raw string misses. You must decode and canonicalize the path first, then validate the result.
Resolve the input against the intended base directory with path.resolve, then confirm the resolved absolute path still starts with the base directory before using it. Reject anything that escapes. Better still, map user input to an allowlist of known files rather than accepting path strings.
Double-encoding encodes an already-encoded value, so %2e becomes %252e (the % itself becomes %25). A filter that decodes once still sees %2e and may miss it, while a later stage decodes fully and exposes the ../. Decode repeatedly until the string stops changing before validating.
No — combine defences. Canonicalize then validate, prefer an allowlist of known files, contain the resolved path within the base directory, and run the process with least-privilege filesystem access so a bypass reaches as little as possible.