Skip to content

no-child-process-interpolated-command misses inline require('child_process').(method)() calls #49067

Description

@github-actions

Summary

eslint-factory/src/rules/no-child-process-interpolated-command.ts detects interpolated/dynamic command strings passed to child_process exec-family methods (exec, execSync, spawn, spawnSync, execFile, execFileSync), but its method-resolution logic only recognizes the callee object when it is a plain Identifier bound to a require'd/imported child_process module (see isChildProcessObjectBinding in eslint-factory/src/rules/try-catch-rule-utils.ts, and the callee.object.type === AST_NODE_TYPES.Identifier check in no-child-process-interpolated-command.ts around line 135-140).

An inline call of the form:

require('child_process').execSync(`rm -rf ${userInput}`);

never binds the child_process module to an identifier - the callee object is itself a CallExpression (the require(...) call), not an Identifier - so isChildProcessObjectBinding/resolveChildProcessMethod never matches, and the rule silently does not fire, even though this is a textbook command-injection sink identical to the const cp = require('child_process'); cp.execSync(...) pattern the rule already correctly flags.

Grounding

No live occurrence of this exact inline-require call shape was found in the current actions/setup/js/**/*.cjs corpus (searched via a pattern matching require('child_process'). or require('node:child_process'). followed directly by exec/execSync/spawn/spawnSync/execFile/execFileSync), so this is a soundness gap rather than an active false negative today. It's filed because it's cheap to close and consistent with the rule's own stated intent (catching command-injection sinks reached through the child_process module regardless of how it's referenced), and because the corpus is disciplined today but a future contributor could easily write the inline form without the rule catching it.

Acceptance Criteria

  • Rule recognizes require('child_process').<method>(...) / require('node:child_process').<method>(...) as a valid child_process method call, in addition to the existing identifier-binding-based resolution.
  • A new invalid test case is added to no-child-process-interpolated-command.test.ts covering require('child_process').execSync(...) (and ideally spawn) with an interpolated/dynamic command argument, asserting the rule reports it.
  • A valid test case confirms non-interpolated/static commands via the same inline-require form are still accepted (no false positive introduced).
  • Existing tests continue to pass; no changes to the rule's shell-true/argv-based sub-checks for spawn/spawnSync/execFile/execFileSync are required beyond the callee-resolution fix.

Scope note

This mirrors a similar shape of gap previously fixed for other rules in this family (destructured/aliased fs bindings in require-fs-sync-try-catch) - a single missing identifier-resolution path for an otherwise well-covered rule.

Generated by 🤖 ESLint Refiner · agent · 236.9 AIC · ⌖ 5.27 AIC · ⊞ 4.9K ·

  • expires on Aug 5, 2026, 10:18 PM UTC-08:00

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions