Skip to content

NEW @W-23906075@ SF CLI - Automatic ESLint config import leads to RCE during code analyzer process - #501

Merged
nikhil-mittal-165 merged 3 commits into
devfrom
feature/W-eslint-rce-declarative-only
Aug 20, 2026
Merged

NEW @W-23906075@ SF CLI - Automatic ESLint config import leads to RCE during code analyzer process#501
nikhil-mittal-165 merged 3 commits into
devfrom
feature/W-eslint-rce-declarative-only

Conversation

@nikhil-mittal-165

Copy link
Copy Markdown
Contributor

Summary

Restricts ESLint's auto-discovery mechanism to declarative configuration only, preventing arbitrary executable config files from being automatically discovered and executed, thus eliminating RCE vector during code analyzer process.

GUS Ticket W-23906075 — [Bug Bounty / H1] SF CLI - Automatic ESLint config import leads to RCE during code analyzer process

Changes

  • eslint-engine: Modified auto-discovery logic to skip executable configuration files and only load declarative ESLint configs; added SkippedAutoDiscoveredExecutableConfigFile warning when auto-discovery encounters executable configs
  • eslint8-engine: Applied same fix to ESLint 8.x variant; maintained explicit opt-in behavior for user-specified eslint_config_file (still executes with ExplicitExecutableConfigFileWillExecute warning)
  • Test suite: Fixed 3 TypeScript compile errors in eslint-engine/test/engine.test.ts (conditional spread operator for eslint_config_file type compatibility)

Test Evidence

  • Unit tests: eslint-engine 329/332 pass (3 skipped, 0 fail after fix), eslint8-engine 99/99 pass
  • Integration: dreamhouse baseline scan 615 violations/165 files, eslint 100% coverage, no crash
  • RCE PoC verification: auto-discovered malicious eslint.config.cjs NOT executed (sentinel absent) with SkippedAutoDiscoveredExecutableConfigFile warning; explicit eslint_config_file opt-in still executes (sentinel present) with ExplicitExecutableConfigFileWillExecute warning
  • 'sf code-analyzer rules' lists 262 rules and exits successfully
  • Test Status: PASS
  • Fix Attempts: 1
  • Known external failures (not blocking): apexguru 404 external service; pmd/cpd/sfge require Java; bare npx-jest experimental-vm-modules env artifact

Dependencies

None

…tive config to prevent RCE

Auto-discovering an executable ESLint config (eslint.config.{js,cjs,mjs} or
legacy .eslintrc.{js,cjs}) caused its top-level JavaScript to execute during
analysis, an arbitrary code execution vector reachable from an untrusted
workspace when auto_discover_eslint_config is enabled.

Auto-discovery now applies only declarative config (.json/.yaml/.yml). An
executable config found by auto-discovery is skipped with a Warn. An explicitly
configured eslint_config_file may still be executable (trusted operator opt-in)
but emits a Warn that its top-level code will run.

Additive only: no exported symbols were removed or renamed.
…ative config to prevent RCE

Mirrors the eslint (flat) engine fix for the legacy ESLint v8 engine. Auto-
discovering an executable legacy config (.eslintrc.{js,cjs}) executed its top-
level JavaScript during analysis via ESLint's own .eslintrc tree-walk
(useEslintrc) and via overrideConfigFile.

Auto-discovery now applies only declarative legacy config (.json/.yaml/.yml):
an auto-discovered executable config is skipped, useEslintrc is disabled so
ESLint will not walk to it either, and a Warn is emitted. An explicitly
configured executable eslint_config_file is still applied (trusted operator
opt-in) but emits a Warn that its top-level code will run.

Additive only: no exported symbols were removed or renamed.
@git2gus

git2gus Bot commented Aug 18, 2026

Copy link
Copy Markdown

Git2Gus App is installed but the .git2gus/config.json doesn't have right values. You should add the required configuration.

@nikhil-mittal-165 nikhil-mittal-165 changed the title @W-23906075@ SF CLI - Automatic ESLint config import leads to RCE during code analyzer process NEW @W-23906075@ SF CLI - Automatic ESLint config import leads to RCE during code analyzer process Aug 18, 2026
@nikhil-mittal-165
nikhil-mittal-165 marked this pull request as ready for review August 18, 2026 16:45

@aruntyagiTutu aruntyagiTutu left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed against the W-23906075 bug-bounty RCE finding (automatic ESLint config discovery executing attacker-controlled JS). Traced the fix beyond the diff to confirm the actual execution paths in both engines:

eslint-engine (ESLint 9 / flat config)

  • isExecutableConfigFile() classifies .js/.cjs/.mjs as executable (config.ts). UserConfigInfo.initIfNeeded() refuses to set userConfigFile when an auto-discovered file is executable, emitting SkippedAutoDiscoveredExecutableConfigFile instead.
  • Verified in eslint-wrapper.ts that createESLintOptions always sets overrideConfigFile: true (disabling ESLint's own auto-detection) and only reaches dynamicallyImport()await import(...) (the actual execution point) when userConfigFile is truthy. Since userConfigFile is left undefined for skipped executable files, there's no path left that would execute them. Explicit opt-in (eslint_config_file) still works and now warns via ExplicitExecutableConfigFileWillExecute.

eslint8-engine (ESLint 8 / legacy config)

  • Same executable/declarative split, correctly scoped to .js/.cjs only (no .mjs, since LEGACY_ESLINT_CONFIG_FILES has no mjs variant — confirmed in config.ts).
  • The subtler risk here is that ESLint 8 does its own internal cascading .eslintrc.* discovery via useEslintrc, independent of this codebase's manual discovery — so just withholding the file path isn't enough. Confirmed strategy.ts's shouldUseEslintrc() correctly forces useEslintrc: false whenever a getSkippedExecutableConfigFile() is present, closing that secondary path. This is the right fix and it's easy to miss.

Tests: sentinel-file-based regression tests (writes a marker file only if the malicious config's top-level code runs) assert absence on auto-discovery and presence on explicit opt-in for both engines — a solid way to prove non-execution rather than just asserting on returned config shape. Existing tests were correctly rewired from relying on auto-discovery executing a config to requiring explicit opt-in, and new coverage for declarative auto-discovered configs (.eslintrc.yml etc.) confirms those still apply with no warning.

Architecture is sound in both engines, the ESLint-8-specific useEslintrc gap is correctly closed, and tests substantiate the fix with actual execution proof rather than config-shape assertions alone. No issues found.

@nikhil-mittal-165
nikhil-mittal-165 merged commit a445e36 into dev Aug 20, 2026
14 of 15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants