# eslint-module-utils@2.14.0 security report (npm)

- Verdict: **Needs review** (risk level: medium)
- Scanned: 2026-10-06T14:16:31.000Z
- Files reviewed: 14
- Findings: 4 medium, 5 low severity findings
- Report: https://security.togoder.click/npm/eslint-module-utils
- Source: Togoder Security (https://security.togoder.click), AI source-code review

## Summary

Togoder Security scanned the npm package eslint-module-utils@2.14.0 on Oct 6, 2026. An AI review of 14 source files produced 4 medium, 5 low severity findings. The overall verdict is medium: the findings flag risky but common patterns (dynamic code, unsafe defaults, broad file or network access) rather than confirmed malware.

## Findings

### [medium] Dynamic module loading with computed input

Finding ID: `NPS-4207CFBE968F`

File: `module-require.js:24`

The moduleRequire function accepts an arbitrary package/module name parameter 'p' and dynamically resolves and requires it using Module._resolveFilename with an internals module. This could allow loading of modules from unexpected locations or paths if 'p' is attacker-controlled, bypassing normal resolution boundaries.

### [medium] Dynamic import fallback chain

Finding ID: `NPS-5F6F9C7491D2`

File: `module-require.js:31`

Falls back to require.main.require(p) and finally require(p) with the same external input, increasing chances of arbitrary module resolution/loading depending on caller-supplied values.

### [medium] Dynamic module loading based on external configuration

Finding ID: `NPS-DFE3301D286D`

File: `parse.js:170`

The parse function uses moduleRequire(parserOrPath) where parserOrPath can be a string derived from ESLint settings ('import/parsers' or context.parserPath). This allows loading arbitrary modules specified in configuration, which could be exploited if an attacker can control ESLint settings to load a malicious module.

### [medium] Dynamic module loading

Finding ID: `NPS-0007316E04DB`

File: `resolve.js:100`

The code dynamically loads resolver modules based on user configuration via requireResolver(), using tryRequire() with paths derived from configuration. It attempts to require 'eslint-import-resolver-<name>', the raw name, and a path resolved relative to the base directory. This dynamic loading of arbitrary modules based on configuration could be abused if the configuration is attacker-controlled, allowing loading of malicious modules.

### [low] Use of undocumented Node.js internals

Finding ID: `NPS-327AA5CEDB96`

File: `module-require.js:14`

Uses Module._nodeModulePaths and Module._resolveFilename, undocumented internal APIs that may change between Node versions and can bypass standard module resolution/security checks. Could be leveraged for path traversal or loading modules outside intended scope.

### [low] Dynamic module loading with computed path

Finding ID: `NPS-9F2955038058`

File: `parse.js:17`

The function getBabelEslintVisitorKeys constructs a file path by replacing 'index.js' with 'visitor-keys.js' in a given parserPath and then dynamically requires it. This could allow loading arbitrary modules if the parserPath is attacker-controlled, though in context it is derived from ESLint settings.

### [low] Top-level code execution on import

Finding ID: `NPS-E3CB3C4C6B26`

File: `resolve.js:13`

The module performs computation and filesystem checks at import time (CASE_SENSITIVE_FS detection via fs.existsSync, and initialization of ModuleCache). This is typical for a library but does execute code upon import.

### [low] Dynamic code compilation

Finding ID: `NPS-6B4747D115E9`

File: `resolve.js:33`

A fallback implementation of createRequire uses Module._compile() to compile and execute dynamically generated code ('module.exports = require;'). While this is a polyfill for older Node versions and only compiles a static string, the use of _compile is a dynamic code execution primitive that could be risky if the filename/path were attacker-controlled.

### [low] Filesystem traversal

Finding ID: `NPS-770C12B00A38`

File: `resolve.js:140`

fileExistsWithCaseSync recursively reads directories using fs.readdirSync to determine case-sensitivity of paths. This is within the scope of resolving module paths and is not outside package scope, but it does perform filesystem access.

## Files reviewed

- `module-require.js` (medium): This utility dynamically resolves and loads arbitrary modules using Node internals and caller-supplied input, which is a supply-chain risk if the input is ever attacker-controlled, though no direct exfiltration, credential harvesting, or execution backdoors are present.
- `parse.js` (medium): The code is a legitimate ESLint plugin utility for parsing, but it dynamically requires modules based on external configuration, which could be a security risk if settings are untrusted.
- `resolve.js` (medium): The code is a legitimate ESLint import resolver plugin with dynamic module loading and a Module._compile polyfill, which are not inherently malicious but could be abused if configuration is attacker-controlled.
- `ModuleCache.js` (safe): Cleared by Jev triage; no further analysis needed
- `contextCompat.js` (safe): Cleared by Jev triage; no further analysis needed
- `declaredScope.js` (safe): Cleared by Jev triage; no further analysis needed
- `hash.js` (safe): Cleared by Jev triage; no further analysis needed
- `ignore.js` (safe): No malicious patterns detected; the file contains legitimate ESLint plugin utility logic for handling ignore patterns and file extensions.
- `moduleVisitor.js` (safe): Cleared by Jev triage; no further analysis needed
- `pkgDir.js` (safe): Cleared by Jev triage; no further analysis needed
- `pkgUp.js` (safe): Cleared by Jev triage; no further analysis needed
- `readPkgUp.js` (safe): No malicious patterns detected; the code only reads and parses package.json files via a local helper module.
- `unambiguous.js` (safe): Cleared by Jev triage; no further analysis needed
- `visit.js` (safe): Cleared by Jev triage; no further analysis needed

AI analysis is guidance, not a guarantee. Methodology: https://security.togoder.click/methodology
