RSTR-PTH-002 — Express res.sendFile / fs.readFile with request input

Summary

Node counterpart of RSTR-PTH-001. The application reads, writes, or streams a file whose path is built from req.params, req.query, or req.body without confining the result to a safe base directory.

Severity

High.

Languages

JavaScript, TypeScript.

What rastray flags

app.get('/file', (req, res) => {
    res.sendFile(req.query.path);                              // ← flagged
});

fs.readFile(req.params.name, (err, data) => { ... });          // ← flagged
fs.writeFileSync(req.body.dest, data);                         // ← flagged

What rastray deliberately does not flag

  • res.sendFile(path.join(SAFE_DIR, basename(req.params.name))) — the basename strips traversal sequences.
  • Constant paths.

How to fix it

Always join the user input onto a fixed base, run it through path.basename to strip ../, and verify the resolved path still sits under the base:

import path from 'node:path';
const BASE = path.resolve('./uploads');

app.get('/file/:name', (req, res) => {
    const safeName = path.basename(req.params.name);
    const target   = path.resolve(BASE, safeName);
    if (!target.startsWith(BASE + path.sep)) {
        return res.sendStatus(404);
    }
    res.sendFile(target);
});

path.resolve collapses any leftover ../; the prefix check then catches symlink escapes.

References