# tsconfig-paths@3.15.0 security report (npm)

- Verdict: **Needs review** (risk level: medium)
- Scanned: 2026-10-06T14:24:49.000Z
- Files reviewed: 21
- Findings: 7 medium, 5 low severity findings
- Report: https://security.togoder.click/npm/tsconfig-paths
- Source: Togoder Security (https://security.togoder.click), AI source-code review

## Summary

Togoder Security scanned the npm package tsconfig-paths@3.15.0 on Oct 6, 2026. An AI review of 21 source files produced 7 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 require with user-controlled path

Finding ID: `NPS-2282D4DC7432`

File: `lib/filesystem.js:20`

readJsonFromDiskSync uses require(packageJsonPath) where the path is provided as a function argument. If an attacker can control this path, it could load arbitrary JavaScript files (not just JSON), potentially leading to code execution. The function name implies JSON reading but require() can execute any .js/.json file.

### [medium] Opaque import and side effect at import time

Finding ID: `NPS-38D162BBCF77`

File: `register.js:1`

This file immediately requires the package root ('.') and calls .register() on whatever that module exports. The actual behavior is hidden in the package root's entry point (typically index.js), so this file itself performs no direct I/O but triggers arbitrary code execution on import. Because .register() is invoked unconditionally at module load, all side effects execute whenever this file is imported, without caller control. Without inspecting the referenced module, the true network, filesystem, or process behavior cannot be ruled out; the pattern is characteristic of packages that execute registration hooks at import time.

### [medium] Potential path traversal / arbitrary file read

Finding ID: `NPS-D55D38E99EC1`

File: `src/filesystem.ts:53`

readJsonFromDiskSync and readJsonFromDiskAsync accept fully caller-supplied paths and read them from disk. No validation is performed to ensure the path stays within the package or an expected directory, enabling reading of arbitrary files if callers pass untrusted input. readJsonFromDiskSync even loads them as code via require().

### [medium] Dynamic code loading

Finding ID: `NPS-8058DF87ECF8`

File: `src/filesystem.ts:54`

readJsonFromDiskSync uses require(packageJsonPath) with a caller-controlled path for dynamic module loading. require() executes the target file as JavaScript. If an attacker can control the path (e.g. to a malicious .js file), this leads to arbitrary code execution. A safer pattern would be fs.readFileSync + JSON.parse.

### [medium] File system read via dynamic input

Finding ID: `NPS-A555C9695677`

File: `src/match-path-sync.ts:129`

The `findFirstExistingPath` function calls `readJson(tryPath.path)` where `tryPath.path` is constructed based on the requested module and base URL. If the `requestedModule` is user-controlled and not properly sanitized, an attacker could potentially cause the function to read arbitrary package.json files on the file system by crafting path traversal sequences. However, the path construction logic is delegated to `TryPath.getPathsToTry`, and this file does not itself sanitize input. This is a potential path traversal risk if consumers pass untrusted input.

### [medium] File system reads outside expected scope

Finding ID: `NPS-C5B83BEBF547`

File: `src/tsconfig-loader.ts:130`

`loadTsconfig` recursively follows `extends` chains and reads arbitrary files via `fs.readFileSync`. Combined with absolute paths or `..` traversal in `extends`, this can access files outside the project directory. No validation confines reads to the package or project scope.

### [medium] Path traversal via extends field

Finding ID: `NPS-6345A7734704`

File: `src/tsconfig-loader.ts:175`

The `loadTsconfigFromExtends` function constructs file paths by joining `currentDir` with the user-controlled `extendedConfigValue` from the tsconfig `extends` field. This allows reading arbitrary JSON/JSON5 files on the filesystem (e.g., `extends: '../../../../etc/secret'`). While this is inherent to tsconfig `extends` behavior and not overtly malicious, it can be abused to read sensitive files if an attacker can control the tsconfig content.

### [low] Unsafe JSON parsing without error handling

Finding ID: `NPS-A5BE1460E185`

File: `lib/filesystem.js:32`

readJsonFromDiskAsync uses JSON.parse(result) without a try/catch block. If the file contains invalid JSON, this will throw an uncaught exception in the callback, potentially crashing the process. While not directly malicious, this is a robustness concern.

### [low] Dynamic module resolution using require.extensions

Finding ID: `NPS-9498306DD2EA`

File: `src/match-path-sync.ts:82`

The code uses `Object.keys(require.extensions)` as a default value for the `extensions` parameter in `matchFromAbsolutePaths`. This accesses all registered file extensions from Node.js's internal `require.extensions` object. While this is a common pattern for resolving paths in TypeScript path mapping (used by tsconfig-paths), accessing `require.extensions` exposes the module system's internal registry and could theoretically be abused if the function is invoked in a malicious context. However, in this specific file, the extensions are only used to generate candidate file paths, not to dynamically load or execute modules.

### [low] File existence probing based on dynamic input

Finding ID: `NPS-8108A761C83D`

File: `src/match-path-sync.ts:117`

The function checks for the existence of files at paths derived from the requested module name (`fileExists(tryPath.path)`). This could be used as an oracle for file system enumeration if an attacker can observe the return values (e.g., via error messages or timing). Again, the risk depends on how consumers use this function and whether `requestedModule` is attacker-controlled.

### [low] Environment variable sourcing from external input

Finding ID: `NPS-70858C29D7AC`

File: `src/tsconfig-loader.ts:40`

`tsConfigLoader` accepts a `getEnv` callback and reads `TS_NODE_PROJECT` and `TS_NODE_BASEURL`. These values flow into `loadSync` and influence file resolution. This is by design (ts-node configuration) but means the module inherits trust from the environment-provided `getEnv`.

### [low] TOCTOU race condition on file type check

Finding ID: `NPS-4F11F693B3FE`

File: `src/tsconfig-loader.ts:99`

`resolveConfigPath` uses `fs.lstatSync(filename).isDirectory()` followed by `path.resolve`, and `fs.statSync(cwd).isFile()` before reading. These check-then-use patterns are susceptible to time-of-check/time-of-use races, though impact is limited in this context.

## Files reviewed

- `lib/filesystem.js` (medium): Utility filesystem module with no obvious malicious patterns, but uses dynamic require() on a caller-supplied path which could enable arbitrary code loading if the path is attacker-controlled.
- `register.js` (medium): This stub unconditionally imports the package root and invokes a hidden register() hook at load time, delegating all potentially malicious behavior to unreviewed code outside this file.
- `src/filesystem.ts` (medium): No outright exfiltration or backdoors, but readJsonFromDiskSync loads an arbitrary, unvalidated file path via require(), which can lead to arbitrary code execution or arbitrary file read if the path is attacker-influenced.
- `src/match-path-sync.ts` (medium): This appears to be the legitimate tsconfig-paths library code for resolving TypeScript path mappings; no overtly malicious patterns like data exfiltration, credential harvesting, or shell execution were found, though the dynamic file system probing based on input may pose a path traversal risk if used with untrusted input.
- `src/tsconfig-loader.ts` (medium): No overt malicious patterns, but the module performs recursive, user-influenced filesystem reads via tsconfig `extends` resolution without scope confinement, which could enable sensitive file disclosure in hostile configurations.
- `lib/config-loader.js` (safe): No malicious patterns detected; the code is a straightforward configuration loader that reads tsconfig.json and environment variables without any exfiltration, code execution, or suspicious behavior.
- `lib/index.js` (safe): No malicious patterns detected
- `lib/mapping-entry.js` (safe): Cleared by Jev triage; no further analysis needed
- `lib/match-path-async.js` (safe): No malicious patterns detected; the code is a legitimate TypeScript path-matching utility with no network, credential, or process-manipulation activity.
- `lib/match-path-sync.js` (safe): No malicious patterns detected; the code is a legitimate TypeScript path-mapping resolver with no network, credential, process, or obfuscation behavior.
- `lib/options.js` (safe): No malicious patterns detected; the file only parses CLI arguments for a project directory path and sets a working directory option.
- `lib/register.js` (safe): The code patches Node's module resolution to support TypeScript path mapping (tsconfig-paths), a standard and legitimate operation with no malicious patterns detected.
- `lib/try-path.js` (safe): Cleared by Jev triage; no further analysis needed
- `lib/tsconfig-loader.js` (safe): No malicious patterns detected
- `src/config-loader.ts` (safe): No malicious patterns detected
- `src/index.ts` (safe): Cleared by Jev triage; no further analysis needed
- `src/mapping-entry.ts` (safe): Cleared by Jev triage; no further analysis needed
- `src/match-path-async.ts` (safe): No malicious patterns detected
- `src/options.ts` (safe): No malicious patterns detected
- `src/register.ts` (safe): No malicious patterns detected
- `src/try-path.ts` (safe): Cleared by Jev triage; no further analysis needed

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