Skip to main content
ESLint Interlace
Plugin: node-securityRules

no-toctou-vulnerability

Detects Time-of-Check-Time-of-Use (TOCTOU) race condition vulnerabilities in file system operations.

Keywords: TOCTOU, time-of-check, time-of-use, race condition, security, ESLint rule, CWE-367

Quick Summary

AspectDetails
SeverityError
CWECWE-367
OWASPA01:2021
Auto-Fix❌ No
Suggestions✅ 3 available
CategorySecurity

Vulnerability and Risk

Vulnerability: A Time-of-Check to Time-of-Use (TOCTOU) vulnerability relies on the timing window between checking a condition (e.g., "does this file exist?") and using the result (e.g., "read the file").

Risk: An attacker can alter the state of the system (e.g., delete or replace the file with a symbolic link) during this window, causing the application to perform actions on the wrong resource. This can lead to privilege escalation, data corruption, or denial of service.

Rule Details

TOCTOU vulnerabilities occur when a program checks a condition (like file existence) and later performs an action based on that check, but the condition may have changed between the check and the action.

Why This Matters

IssueImpactSolution
🔒 Race ConditionAttackers can exploit timing windowUse atomic operations
🐛 Data IntegrityFile state may change unexpectedlyUse fs.promises API
ReliabilityOperations may fail or produce wrong resultsHandle errors properly

Configuration

interface Options {
  /** Ignore in test files. Default: true */
  ignoreInTests?: boolean;

  /** File system methods to check. Default: ['fs.existsSync', 'fs.statSync', 'fs.accessSync'] */
  fsMethods?: string[];
}

Examples

❌ Incorrect

// TOCTOU vulnerability: file state can change between check and use
if (fs.existsSync('config.json')) {
  const data = fs.readFileSync('config.json'); // ⚠️ File may no longer exist
}

// Stat-then-use pattern
const stats = fs.statSync('file.txt');
if (stats.isFile()) {
  fs.unlinkSync('file.txt'); // ⚠️ File may have changed
}

✅ Correct

// Use try-catch with fs.promises (atomic behavior)
try {
  const data = await fs.promises.readFile('config.json');
  // Process data
} catch (err) {
  if (err.code === 'ENOENT') {
    // File doesn't exist - handle appropriately
  }
}

// Use proper locking for concurrent access
import { lock } from 'proper-lockfile';

const release = await lock('file.txt');
try {
  const data = await fs.promises.readFile('file.txt');
  await fs.promises.writeFile('file.txt', modifiedData);
} finally {
  await release();
}

Configuration Examples

Basic Usage

// eslint.config.mjs
export default [
  {
    rules: {
      'node-security/no-toctou-vulnerability': 'error',
    },
  },
];

Custom Configuration

// eslint.config.mjs
export default [
  {
    rules: {
      'node-security/no-toctou-vulnerability': [
        'error',
        {
          ignoreInTests: true,
          fsMethods: ['fs.existsSync', 'fs.statSync', 'fs.accessSync'],
        },
      ],
    },
  },
];

LLM-Optimized Output

🔒 CWE-367 OWASP:A01-Broken-Access-Control CVSS:7.0 | TOCTOU vulnerability | HIGH
   Fix: Use atomic operations or fs.promises for file operations | https://cwe.mitre.org/data/definitions/367.html

Suggestions

When this rule reports an error, it provides three suggestions:

  1. Use Atomic Operations - Use atomic file operations like fs.promises.access() then fs.promises.readFile()
  2. Use fs.promises - Use the Promise-based fs API for better error handling
  3. Add Proper Locking - Use a file locking library like proper-lockfile for concurrent access

Known False Negatives

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

Values from Variables

Why: Values stored in variables are not traced.

// ❌ NOT DETECTED - Value from variable
const value = userInput;
dangerousOperation(value);

Mitigation: Validate all user inputs.

Wrapper Functions

Why: Custom wrappers not recognized.

// ❌ NOT DETECTED - Wrapper
myWrapper(userInput); // Uses dangerous API internally

Mitigation: Apply rule to wrapper implementations.

Dynamic Invocation

Why: Dynamic calls not analyzed.

// ❌ NOT DETECTED - Dynamic
obj[method](userInput);

Mitigation: Avoid dynamic method invocation.

Further Reading