noctcore-security/require-path-containment
Request-shaped input flowing directly into
path.join/path.resolvewithout a containment guard is a path-traversal sink. Opt-in — not inrecommended.
Recommended preset: not included · Autofix: no · Suggestions: no · Type information: not needed
// `../../../etc/passwd` escapes the intended directoryconst file = path.join(baseDir, req.params.file);A crafted req.params.file of ../../etc/passwd walks out of baseDir and reads an arbitrary file.
The safe pattern is to resolve, then verify the result still lives under the base directory before
touching the filesystem:
// verify containmentconst resolved = path.resolve(baseDir, req.params.file);if (!resolved.startsWith(baseDir)) throw new ForbiddenError();What it flags
Section titled “What it flags”Deliberately narrow to stay high-precision without type information. It fires only when:
- a
req.*/request.*member expression is passed directly intopath.join(...)orpath.resolve(...), and - the enclosing function contains no containment guard.
A guard is any path.normalize / path.relative / .startsWith(...) call in the same function, or
the escape-hatch comment convention (below).
Escape hatch
Section titled “Escape hatch”If a flagged site is already safe, add a comment containing path-containment anywhere in the
function:
function serve(req) { // path-containment: base is a fixed constant and req.params.file is validated upstream return path.join(base, req.params.file);}What it does not flag
Section titled “What it does not flag”Because a sanitized value is normally bound to a local first (const safe = clean(req.x) →
path.join(base, safe)), that shape is not a direct req.* argument and is never flagged.
// sanitized into a local: not a direct req.* argumentconst safe = sanitize(req.params.file);return path.join(base, safe);Broader user-input sources — arbitrary handler parameters, decoded JWT/payload fields — are out of
scope. Proving them user-shaped needs type or dataflow analysis this syntactic rule cannot do
soundly, and guessing would flood the codebase with false positives. Only the unambiguous req.* /
request.* root is tracked.
Options
Section titled “Options”| Option | Type | Default | Meaning |
|---|---|---|---|
requestObjects |
string[] |
['req', 'request'] |
Root object names treated as request-shaped input. |
'noctcore-security/require-path-containment': ['error', { requestObjects: ['req', 'request', 'ctx'] }]When not to use it
Section titled “When not to use it”This is a high-false-positive family, which is why it is omitted from the recommended preset.
Enable it explicitly at error once you have confirmed your codebase’s req.*-into-path call
sites are worth auditing; scope it with files to the directories you are ready to fix.