# prettier@3.9.9 security report (npm)

- Verdict: **Needs review** (risk level: medium)
- Scanned: 2026-10-06T14:23:53.000Z
- Files reviewed: 9
- Findings: 1 medium, 6 low severity findings
- Report: https://security.togoder.click/npm/prettier
- Source: Togoder Security (https://security.togoder.click), AI source-code review

## Summary

Togoder Security scanned the npm package prettier@3.9.9 on Oct 6, 2026. An AI review of 9 source files produced 1 medium, 6 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-D4F4C8FA571B`

File: `internal/experimental-cli-worker.mjs:3353`

The getModule function performs a dynamic import using a path derived from runtime input (modulePath). The path is ultimately constructed from the plugin name supplied in formatOptions.plugins. Although getPluginPath attempts to resolve the plugin under the current working directory's index.js, the fallback getModulePath(name, rootPath) invokes Node's module resolution, which can resolve bare specifiers and potentially load arbitrary modules. If plugins or their names are attacker-controlled (e.g., via configuration or input), this can lead to loading and executing untrusted code.

### [low] Dynamic code execution

Finding ID: `NPS-28C7E3257498`

File: `bin/prettier.cjs:68`

Uses new Function('module', 'return import(module)') to perform dynamic import. While this is a known pattern in Prettier's CLI launcher to load ESM from CJS, use of new Function constitutes dynamic code execution and could be abused if the module path were attacker-controlled.

### [low] Dynamic imports with computed/external input

Finding ID: `NPS-114EA379F10F`

File: `bin/prettier.cjs:71`

Dynamically imports ../internal/experimental-cli.mjs or ../internal/legacy-cli.mjs based on environment variable PRETTIER_EXPERIMENTAL_CLI and command-line flag. Module paths are hardcoded relative paths, so risk is limited, but behavior is influenced by env/CLI input.

### [low] Process signal handling and termination

Finding ID: `NPS-2439F9063387`

File: `internal/experimental-cli-worker.mjs:1088`

The when-exit Interceptor registers handlers for numerous signals (SIGHUP, SIGINT, SIGTERM, SIGALRM, SIGABRT, etc.) and can call process.kill(process.pid, signal) to re-raise signals. This alters default process termination behavior and could interfere with expected signal semantics in a parent process.

### [low] Top-level side effect: process exit interceptor registration

Finding ID: `NPS-779757DFA076`

File: `internal/experimental-cli-worker.mjs:1187`

The when-exit module (node_default(Temp.purgeSyncAll)) registers signal handlers and an exit hook at import time. This runs code on import without user interaction, manipulating process exit behavior. While common for cleanup utilities, it is a top-level side effect that modifies global process state.

### [low] File system manipulation outside package scope

Finding ID: `NPS-EFCD6A2C7338`

File: `internal/experimental-cli-worker.mjs:2990`

The ionstore NodeStore writes to a predictable temporary file in os.tmpdir() (ionstore_<id>.json). The id is validated by a regex in the AbstractStore constructor, limiting the risk, but the library still reads/writes files outside its package directory, which could potentially be abused if ids or data are influenced by external input.

### [low] Dynamic module loading (benign)

Finding ID: `NPS-9B7A98921B4D`

File: `plugins/graphql.mjs`

The code uses process.getBuiltinModule('node:diagnostics_channel') wrapped in try/catch to optionally load a Node.js built-in module for tracing. This is a legitimate feature for telemetry hooks, not external code loading.

## Files reviewed

- `bin/prettier.cjs` (medium): The file is a legitimate Prettier CLI launcher that uses a dynamic import wrapper and environment/CLI-controlled branching, but contains no data exfiltration, credential harvesting, obfuscation, or malicious behavior.
- `internal/experimental-cli-worker.mjs` (medium): No obvious malicious exfiltration or credential harvesting was found, but the code contains dynamic module loading from computed paths and global process/FS side effects that warrant caution.
- `doc.js` (safe): No malicious patterns detected; the file is a UMD bundle of Prettier's document printer with no network, filesystem, process, or dynamic code execution behaviors.
- `doc.mjs` (safe): No malicious patterns detected; the file contains standard Prettier-style document printing utilities with no network, filesystem, process, or dynamic code execution behavior.
- `index.cjs` (safe): This is a bundled build of the Prettier library (version 3.9.9) containing only legitimate formatting utilities, text-processing shims, and standard ESM-to-CJS interop helpers with no malicious patterns.
- `plugins/graphql.js` (safe): No malicious patterns detected; this is a legitimate Prettier GraphQL plugin with only benign Node.js diagnostics_channel usage for optional tracing.
- `plugins/graphql.mjs` (safe): This is the Prettier GraphQL plugin; it contains only parser/printer logic with no malicious patterns, network activity, credential access, process spawning, or obfuscation.
- `standalone.js` (safe): This is the standard Prettier standalone bundle (v3.9.9); no malicious patterns, exfiltration, obfuscation, or suspicious behavior detected.
- `standalone.mjs` (safe): No malicious patterns detected; the file is a minified bundle of the Prettier code formatter with no exfiltration, credential harvesting, dynamic code execution, or network/process activity.

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