Summary
Togoder Security scanned the npm package @npmcli/arborist@9.9.1 on Oct 6, 2026. An AI review of 64 source files produced 1 medium, 15 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 16
Dynamic module loading with computed input
NPS-D47B070F1A17
The code dynamically reads all .js files from the current directory and requires them using a computed path: require(./${file}). While this is a common CLI pattern for loading command modules, it does execute arbitrary code from any .js file in the bin directory. If an attacker could add a malicious file to this directory, it would be executed. In the context of a third-party package, this is a moderate concern but typical for CLI tools.
File system manipulation
NPS-808869B7898F
When options.saveHidden is true, the code sets tree.meta.filename to a path constructed from options.path + '/node_modules/.package-lock.json' and writes to it via tree.meta.save(). This writes to node_modules/.package-lock.json which is outside the typical package scope, though it is within the hybrid tree structure. This could be used to persist configuration or metadata outside expected boundaries.
Top-level code execution on import
NPS-330EF84C3885
The file executes top-level code immediately when run, including reading the directory, requiring all command files, and dispatching a command. This is expected for a CLI entry point but means any import of this file triggers filesystem reads and module loading.
File system read outside package scope
NPS-2A22A22634BE
fs.readdirSync(__dirname) reads the bin directory to discover command files. This is scoped to the package's own bin directory, not outside package scope, so it is low risk.
File system manipulation outside package scope
NPS-9A041FDE3478
The code writes log output to a user-specified logfile via options.logfile. It creates directories recursively with fs.mkdirSync and opens the file in append mode with fs.openSync. This behavior is expected for a logging utility and is controlled by user configuration, but it does write outside the package directory.
Top-level code execution at import time
NPS-66E4763EC6AE
The module registers event listeners on import, which executes code at load time. However, this is benign and part of the module's intended functionality.
Custom event listener on process
NPS-37C361BC5376
The code listens for a non-standard 'time' event on the process object, which is unusual but not inherently malicious; it appears to be an internal API for performance timing.
Path traversal risk mitigated
NPS-F295B1B370D8
Uses nameFromFolder() to sanitize package names before joining into filesystem paths (e.g., ${safeName}@${node.version} under node_modules/.store). Comments explicitly note stripping path traversal from package.json name fields. This appears to be a defensive measure rather than a vulnerability.
Package extraction to filesystem
NPS-CAF23B882D36
Calls pacote.extract(node.resolved, dir, ...) to download and extract tarballs from registry/resolved URLs into node_modules/.store. This is normal npm Arborist functionality for installing dependencies, not exfiltration, but does write files and make network requests to resolved package URLs.
Recursive tree recreation with user-controlled options
NPS-4D0C3F7CE484
On shrinkwrap nodes, creates a new Arborist instance with { ...this.options, path: dir } and recursively calls buildIdealTree/makeIdealGraph. Options are inherited from the parent npm invocation. No suspicious option injection beyond what npm normally supports.
No dynamic code execution
NPS-D9026F03ED62
No use of eval, new Function, vm, child_process, shell commands, or dynamic requires with computed paths. crypto is used only for hashing (shake256), not for any key/credential material.
No credential or environment harvesting
NPS-BA12D425DFF8
No reads of ~/.npmrc, ~/.ssh, ~/.aws, environment variables, or browser data. No outbound requests beyond expected pacote.extract calls to resolved package tarball URLs.
Filesystem existence check
NPS-DB61B83B88C2
The code uses existsSync to check whether binary paths exist as part of diffing node trees. This is a legitimate local file existence check and does not read or exfiltrate file contents.
Tree mutation during diff
NPS-A635B77436A4
The diff logic mutates the input trees by reassigning node.parent for bundled dependencies. This is documented as a deliberate performance optimization, not a security issue, though it could have unintended side effects in consumers.
Signal handling logic
NPS-617841539AF5
The code handles process signals to perform cleanup and re-raises the caught signal; this is benign and common in CLI tools.
Retry without nonce on package spec resolution
NPS-96057EEFD5F3
If resolving with the passed-in name and version fails, the fallback at the end attempts npa.resolve(name, lock.version, where) again, without changing parameters, then returns {}. This is benign but could produce misleading results for a lockfile handling utility. No actual malicious behavior detected.
Files reviewed
| File | Verdict | What the reviewer saw |
|---|---|---|
| bin/actual.js | medium | This file appears to be a legitimate part of the npm Arborist library for loading and saving package trees, with one minor file system write concern when saveHidden is enabled. |
| bin/index.js | medium | This appears to be a legitimate CLI entry point for npm's arborist tool with no clear malicious patterns, though it dynamically loads all .js files in its directory which is a minor risk if the package directory could be tampered with. |
| lib/arborist/isolated-reifier.js | medium | This is npm's Arborist isolated-mode reifier; it performs expected dependency resolution, hashing, and tarball extraction with defensive path sanitization, and contains no malicious patterns or exfiltration behavior. |
| lib/spec-from-lock.js | medium | Code appears to be a clean, benign helper extracted from npm v6 for resolving lockfile specs; no malicious patterns, exfiltration, or dangerous execution detected. |
| bin/audit.js | safe | No malicious patterns detected |
| bin/funding.js | safe | No malicious patterns detected; the file simply loads package metadata and prints funding information. |
| bin/ideal.js | safe | No malicious patterns detected |
| bin/lib/logging.js | safe | No malicious patterns detected; the code is a standard logging utility with expected file system access controlled by user configuration. |
| bin/lib/options.js | safe | No malicious patterns detected; this is a standard CLI option parser for npm/arborist with no network, credential, or execution risks. |
| bin/lib/print-tree.js | safe | Cleared by Jev triage; no further analysis needed |
| bin/lib/timers.js | safe | The code is a benign internal timing utility with no malicious patterns such as data exfiltration, credential harvesting, or dynamic code execution. |
| bin/license.js | safe | No malicious patterns detected; the code is a legitimate CLI module for npm's Arborist that queries and logs license information from a dependency tree. |
| bin/prune.js | safe | The code is a standard npm CLI subcommand for pruning extraneous packages with no malicious patterns, network requests, or filesystem access outside normal package operations. |
| bin/reify.js | safe | No malicious patterns detected; the file is a legitimate CLI wrapper for npm's Arborist dependency reification with no suspicious behavior. |
| bin/shrinkwrap.js | safe | No malicious patterns detected in bin/shrinkwrap.js; the code only loads and serializes a lockfile without network, process, or filesystem side effects. |
| bin/virtual.js | safe | No malicious patterns detected |
| lib/add-rm-pkg-deps.js | safe | Cleared by Jev triage; no further analysis needed |
| lib/arborist/build-ideal-tree.js | safe | This file is a legitimate part of npm's arborist dependency tree builder, with no malicious patterns such as data exfiltration, credential harvesting, obfuscated code, backdoors, or suspicious network/process activity detected. |
| lib/arborist/index.js | safe | No malicious patterns detected; this is legitimate npm arborist tree management code. |
| lib/arborist/load-actual.js | safe | No malicious patterns detected; the file is a legitimate npm Arborist module for loading the actual dependency tree with no data exfiltration, credential harvesting, obfuscation, process spawning, or other suspicious behavior. |
| lib/arborist/load-virtual.js | safe | No malicious patterns detected; the code is a legitimate npm arborist virtual tree loader with path traversal protections. |
| lib/arborist/rebuild.js | safe | This is legitimate npm arborist rebuild logic that runs standard package lifecycle scripts, bin linking, and node-gyp detection with no data exfiltration, credential harvesting, obfuscation, or backdoor patterns. |
| lib/arborist/reify.js | safe | This is npm's legitimate arborist reify implementation for package installation, with no malicious patterns such as exfiltration, credential harvesting, obfuscation, or backdoors; all network and filesystem operations are standard package-manager behaviors. |
| lib/audit-report.js | safe | No malicious patterns detected; this is a legitimate npm audit report module that communicates only with the configured registry endpoint for vulnerability advisories. |
| lib/calc-dep-flags.js | safe | Cleared by Jev triage; no further analysis needed |
Show 39 more files
| File | Verdict | What the reviewer saw |
|---|---|---|
| lib/can-place-dep.js | safe | Cleared by Jev triage; no further analysis needed |
| lib/case-insensitive-map.js | safe | Cleared by Jev triage; no further analysis needed |
| lib/consistent-resolve.js | safe | Cleared by Jev triage; no further analysis needed |
| lib/debug.js | safe | No malicious patterns detected; the file contains only benign debug logging logic gated by environment variables and working directory checks. |
| lib/deepest-nesting-target.js | safe | Cleared by Jev triage; no further analysis needed |
| lib/dep-valid.js | safe | No malicious patterns detected; the code is a standard npm dependency validation module with no network, credential, execution, or filesystem manipulation beyond path comparison. |
| lib/diff.js | safe | No malicious patterns detected; the file is a legitimate npm dependency diff implementation using standard tree traversal and integrity checking without network, credential, or code execution activity. |
| lib/edge.js | safe | No malicious patterns detected; the code is a legitimate npm dependency graph edge implementation with no network, process, filesystem, or credential-harvesting behavior. |
| lib/from-path.js | safe | Cleared by Jev triage; no further analysis needed |
| lib/gather-dep-set.js | safe | Cleared by Jev triage; no further analysis needed |
| lib/index.js | safe | Cleared by Jev triage; no further analysis needed |
| lib/install-scripts.js | safe | No malicious patterns detected |
| lib/inventory.js | safe | Cleared by Jev triage; no further analysis needed |
| lib/isolated-classes.js | safe | Cleared by Jev triage; no further analysis needed |
| lib/link.js | safe | Cleared by Jev triage; no further analysis needed |
| lib/node.js | safe | No malicious patterns detected; the code is a legitimate part of the npm CLI's Arborist dependency tree management library. |
| lib/optional-set.js | safe | Cleared by Jev triage; no further analysis needed |
| lib/override-resolves.js | safe | Cleared by Jev triage; no further analysis needed |
| lib/override-set.js | safe | No malicious patterns detected; the file contains only package override resolution logic using standard npm libraries without network, filesystem, process, or environment access. |
| lib/packument-cache.js | safe | Cleared by Jev triage; no further analysis needed |
| lib/peer-entry-sets.js | safe | Cleared by Jev triage; no further analysis needed |
| lib/place-dep.js | safe | No malicious patterns detected; the code is a legitimate npm dependency placement module with no network, filesystem, or process execution risks. |
| lib/printable.js | safe | Cleared by Jev triage; no further analysis needed |
| lib/query-selector-all.js | safe | No malicious patterns detected; the code is a legitimate npm query selector implementation that only performs expected registry audit and packument requests. |
| lib/realpath.js | safe | No malicious patterns detected; the code is a legitimate realpath implementation using Node.js fs and path modules with caching. |
| lib/release-age-exclude.js | safe | Cleared by Jev triage; no further analysis needed |
| lib/relpath.js | safe | Cleared by Jev triage; no further analysis needed |
| lib/reset-dep-flags.js | safe | Cleared by Jev triage; no further analysis needed |
| lib/retire-path.js | safe | Cleared by Jev triage; no further analysis needed |
| lib/script-allowed.js | safe | This file implements an allowScripts policy matcher that carefully uses trusted registry URL identities rather than attacker-controllable package.json fields, with no data exfiltration, process spawning, or other malicious patterns. |
| lib/shrinkwrap.js | safe | The code is a legitimate npm lockfile management module with no malicious patterns detected. |
| lib/signal-handling.js | safe | No malicious patterns detected; the code is a standard signal handler for cleanup on exit. |
| lib/signals.js | safe | Cleared by Jev triage; no further analysis needed |
| lib/tracker.js | safe | Cleared by Jev triage; no further analysis needed |
| lib/tree-check.js | safe | Cleared by Jev triage; no further analysis needed |
| lib/unreviewed-scripts.js | safe | No malicious patterns detected; the code is a legitimate allowScripts walker for npm's arborist with no network, credential, process, or execution concerns. |
| lib/version-from-tgz.js | safe | No malicious patterns detected; the code is a straightforward utility for parsing version information from tarball filenames. |
| lib/vuln.js | safe | Cleared by Jev triage; no further analysis needed |
| lib/yarn-lock.js | safe | Cleared by Jev triage; no further analysis needed |
Scanned versions of @npmcli/arborist
| Version | Verdict | Files | Scanned |
|---|---|---|---|
| 9.9.1 | Needs review | 64 | Oct 6, 2026 |
Frequently asked questions
Is @npmcli/arborist safe to use?
No confirmed malware was found in @npmcli/arborist@9.9.1, but the review flagged 1 medium, 15 low severity findings for risky patterns worth checking before you rely on it.
Does @npmcli/arborist contain malware?
No malware was identified in @npmcli/arborist@9.9.1 when Togoder Security scanned it on Oct 6, 2026. A new version can still introduce malicious code, so scan the exact versions in your lockfile.
How was @npmcli/arborist checked?
Togoder Security downloaded the published npm package and had an AI model read its 64 source files, looking for install scripts, credential access, network exfiltration, obfuscation, backdoors and crypto-wallet theft. The results are cached by file hash and shown here.
How do I scan @npmcli/arborist together with the rest of my dependencies?
Upload your lockfile at https://security.togoder.click/scan or call the API documented at https://security.togoder.click/api-docs. Files that have already been scanned, like the ones in @npmcli/arborist@9.9.1, cost nothing.