Path traversal: reading files outside the intended folder

When a request supplies part of a file path, ../ walks up out of the folder you meant and into the rest of the file system.

Example

Vulnerable
app.get("/files", (req, res) => {
  res.sendFile(path.join(__dirname, "uploads", req.query.name));
});
Fixed
const BASE = path.resolve(__dirname, "uploads");

app.get("/files", (req, res) => {
  const target = path.resolve(BASE, String(req.query.name));
  if (!target.startsWith(BASE + path.sep)) return res.sendStatus(400);
  res.sendFile(target);
});

How it happens

Download endpoints, image resizers and template loaders join a base folder with a name from the request. path.join does not stop ../../../../etc/passwd; neither does checking that the string starts with the folder name before it is resolved. Writes are worse than reads: overwriting a startup script or a template turns traversal into code execution.

How to fix it

Resolve first, then check.

  • Map an identifier to a stored path on the server instead of accepting paths
  • Otherwise resolve the full path and confirm it is still inside the base directory
  • Use path.basename when only a file name is expected
  • Run the process with the least file-system access it needs

How RepoVerse finds it

  • HighRequest input becomes a filesystem path

    `../` sequences walk out of the intended directory and read or overwrite any file the process can reach.

    data flow · CWE-22

  • ModerateRequest value joined into a filesystem path

    A path is built from something that arrived with the request.

    pattern

Questions

Does URL-decoding matter for path traversal?
Yes. Encoded forms such as %2e%2e%2f decode to ../ before the file system sees them, so checks must run on the decoded, resolved path.
How does RepoVerse find path traversal?
It traces request input into fs calls and res.sendFile, res.download and similar sinks, and treats basename() and literal-led paths as safe.

Related

Updated 2026-10-11