Skip to main content
interlace
Plugin: node-securityRules

no-arbitrary-file-access

Prevents file system access with unsanitized user input to protect against path traversal attacks.

⚠️ This rule errors by default in the recommended config.

Quick Summary

AspectDetails
CWE ReferenceCWE-22 (Improper Limitation of Pathname)
OWASPA01:2021 Broken Access Control
SeverityHigh
CategorySecurity

Rule Details

Path traversal vulnerabilities allow attackers to access files outside the intended directory using sequences like ../. This rule detects fs.* calls where the path comes from user input.

The sink is the fs module however it is reached: fs.readFile, fs.promises.readFile, a default, namespace or named import from fs/promises (import fsp from 'fs/promises', import { readFile } from 'node:fs/promises'), require('fs').promises, and fs imported under another name.

Smart Detection: This rule recognizes safe patterns including:

  • path.basename() sanitization
  • path.join() whose request-derived parts all pass through path.basename() — one basename argument does not clear the others: path.join(ROOT, req.query.folder, name) still escapes ROOT with folder = '../../etc'
  • startsWith() validation guards

Examples

❌ Incorrect

// A request-derived path
fs.readFileSync(req.query.file, 'utf8');

// `process.argv` is user input too
fs.readFileSync(process.argv[2], 'utf8');

// Destructured from the request — the same value as `req.query.file`
const { file } = req.query;
fs.readFileSync(file, 'utf8');

// Assigned after the declaration
let target;
target = req.query.file;
await fsp.readFile(target);

// A safe-sounding parameter, filled with request input by a caller in this file
function readSafe(safePath) {
  return fs.readFileSync(safePath);
}
readSafe(req.query.file);

✅ Correct

fs.readFileSync('./config.json');

Error Message Format

The rule provides LLM-optimized error messages (Compact 2-line format) with actionable security guidance:

🔒 CWE-22 OWASP:A01 CVSS:7.5 | Path Traversal detected | HIGH [SOC2,PCI-DSS,HIPAA,ISO27001]
   Fix: Review and apply the recommended fix | https://owasp.org/Top10/A01_2021/

Message Components

ComponentPurposeExample
Risk StandardsSecurity benchmarksCWE-22 OWASP:A01 CVSS:7.5
Issue DescriptionSpecific vulnerabilityPath Traversal detected
Severity & ComplianceImpact assessmentHIGH [SOC2,PCI-DSS,HIPAA,ISO27001]
Fix InstructionActionable remediationFollow the remediation steps below
Technical TruthOfficial referenceOWASP Top 10

Known False Negatives

The following patterns are not detected due to static analysis limitations:

Indirect User Input

Why: Data flow through multiple variables not traced.

// ❌ NOT DETECTED - Indirect flow
const userPath = getPathFromRequest(req);
fs.readFileSync(userPath);

Mitigation: Apply validation at the source.

Custom File Wrappers

Why: Wrapper functions around fs not analyzed.

// ❌ NOT DETECTED - Custom wrapper
function readUserFile(path) {
  return fs.readFileSync(path); // Called with user input elsewhere
}

Mitigation: Apply rule to wrapper implementations.

Paths This Rule Cannot Attribute To A Source

Why: This rule reports "file path from user input", so it stays silent when there is no visible input to point at — a bare global, an unresolved import, a parameter no call site in the file fills in. Reporting those said something untrue and duplicated detect-non-literal-fs-filename at a second severity.

// ❌ NOT DETECTED - nothing here names a source
fs.readFile(userFile, cb);

Mitigation: detect-non-literal-fs-filename owns these; the two rules partition rather than overlap. process.argv is on this rule's side of that split, which is the handoff that rule's own docs describe. process.env is not reported: that delegation is conditional on treating the environment as attacker-controlled, and an env var is normally operator configuration — fs.readFileSync(process.env.CA_BUNDLE) is an operator pointing a client at a certificate, not a traversal.

When Not To Use It

  • In CLI tools where file paths come from command-line arguments, if you treat process.argv as trusted (this rule does not — it reports those paths)
  • In build scripts processing known file trees
  • When using a file access abstraction layer with built-in validation

Further Reading


Category: Security
Type: Problem
Recommended: Yes

Use this rule

npm install -D oxlint-plugin-node-security
.oxlintrc.json
{  "jsPlugins": ["oxlint-plugin-node-security"],  "rules": {    "node-security/no-arbitrary-file-access": "error"  }}
vite.config.ts
import { defineConfig } from 'vite-plus';export default defineConfig({  lint: {    jsPlugins: ['oxlint-plugin-node-security'],    rules: {      'node-security/no-arbitrary-file-access': 'error',    },  },});

oxlint-plugin-node-security re-exports eslint-plugin-node-security/oxlint: the same rules under the same IDs, and no ESLint install. Why oxlint.

Did this rule catch something? Star the repo to get new CWE coverage as we ship it — or follow the AI-code-security benchmarks behind these rules.