Summary
Togoder Security scanned the npm package rolldown@1.2.11 on Oct 6, 2026. An AI review of 30 source files produced 2 high, 9 medium, 13 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 24
Dynamic import with external input
NPS-CB4CA2815594
The HMR update handler calls import(data.path) using the path field from a WebSocket message. If the WebSocket server (ws://$ADDR) is compromised or spoofed, this allows arbitrary module loading/execution from attacker-controlled paths. This is a dynamic import with computed/external input.
Remote script injection
NPS-F2A43036C59C
In non-Node environments, loadScript(data.url) creates and appends a <script> element with src from the WebSocket message, executing remotely-supplied JavaScript. Combined with the insecure ws:// scheme (not wss://), this enables remote code execution via MITM or hostile server.
Insecure WebSocket connection
NPS-0697663D6906
The WebSocket is established over unencrypted ws:// (line 66: new URL('ws://$ADDR')), allowing network attackers to intercept or inject HMR messages (including hmr:update payloads) leading to code execution.
Code execution via runtime message handling
NPS-C9AE3FBEA6F0
Top-level code establishes a WebSocket listener that executes server-controlled module paths/URLs on receipt of hmr:update messages. While typical for HMR runtimes, the lack of origin/authentication validation makes this a powerful code-execution primitive.
Dynamic import with computed input
NPS-77EA1506F366
The code dynamically imports a module using pluginInfo.fileUrl, which comes from workerData. This value is passed to the worker thread from the parent process and is not validated or restricted within this file. If an attacker can control workerData, they could load and execute arbitrary code.
Network download and package installation at runtime
NPS-29E3D70A3BD2
The webcontainer fallback path, when running inside a WebContainer environment, deletes /tmp/rolldown-<version>, recreates it, and executes pnpm i @rolldown/binding-wasm32-wasi@<version> via childProcess.execFileSync to download and install a package from the registry at runtime. While this is a known fallback mechanism for WebContainer environments and uses the package manager rather than direct curl/wget, it performs network fetch and process spawning triggered by top-level/import-time code, which is a supply-chain risk if the registry entry is compromised.
Dynamic module loading with environment variable path
NPS-ECF18A27274C
If process.env.NAPI_RS_NATIVE_LIBRARY_PATH is set, the code calls __require(process.env.NAPI_RS_NATIVE_LIBRARY_PATH) to load an arbitrary native module. This allows an attacker who can set that environment variable (or a malicious CI/dev environment) to load arbitrary code. This is an intentional escape hatch but is a risky pattern because it trusts an env var to specify a module path.
Module hook registration at import time
NPS-1C7F69324815
createOnThreadImporter() calls Module.registerHooks({ resolve }) at module load time (when createImporter() is first invoked). Module hooks allow interception and rewriting of all import resolutions in the process, which is a powerful capability that could be abused. The code propagates tracking queries through the resolve hook, mutating result.url in place for relative file imports.
Dynamic module loading with computed input
NPS-C15354C36C7A
The freshImport() function dynamically imports modules using a computed specifier built at runtime (specifier + formatTrackingQuery(...)). This pattern caches-busts Node's module cache and re-evaluates modules in a fresh graph. While this is the intended functionality of the 'fresh-import' package, dynamic imports with computed input can be abused to execute arbitrary code if the specifier is attacker-controlled.
Dynamic code import and execution
NPS-592DFA152D7E
The module dynamically imports JS/TS config files specified by the user and executes them. It also bundles TS configs via rolldown and writes the bundled output next to the original config file before importing it. While this is a legitimate config-loading feature used by Rolldown, it involves executing arbitrary code from config files and creating temporary files on disk.
Dynamic code execution
NPS-E3F7C0B8221C
The code uses new Function(...) inside createMerger(fnCount) to dynamically construct a function body from generated strings. Although the input fnCount is derived from the number of visitor functions (internal count, not directly attacker-controlled), this pattern is a dynamic code generation red flag. It is part of the legitimate oxc-parser visitor optimization, but it is worth noting.
Module compile cache manipulation
NPS-9E6EEFC0920C
The code uses module.enableCompileCache and module.flushCompileCache. These are experimental Node.js features that cache compiled JavaScript modules. While not inherently malicious, they can be used to persist code execution artifacts on disk and may be abused to load cached malicious code across runs. The try/catch blocks suppress errors, which is common but can hide failures.
Dynamic import
NPS-2F44B3AFD7CF
The file dynamically imports '../dist/cli.mjs' at the top level. While the path is static and relative, dynamic imports can be used to execute code that is not statically analyzable. This is a common pattern for CLI tools, but it is worth noting as it runs code at import time.
Top-level async execution
NPS-651352286B35
The code executes an async IIFE immediately on module import, registering plugins and communicating with the parent thread. This is expected for a worker entry point, but it runs automatically without any guard, which could be abused if the module is imported in an unexpected context.
Potential error information exposure
NPS-14034D7277FA
The catch block posts the entire error object to the parent thread. Depending on the nature of the error, this could leak sensitive internal details (e.g., stack traces, file paths) to the parent process.
Process spawning and shell command execution
NPS-4D5E2DCA2AE3
Uses child_process.execFileSync('pnpm', ['i', bindingPkg]) to install a package, and child_process.execSync('ldd --version') to detect musl libc. These are process-spawning operations, though the arguments are not derived from untrusted external input and are part of standard native binding loading logic.
File system manipulation outside package scope
NPS-9F8415D2DDA2
In the WebContainer fallback, the code performs fs.rmSync(baseDir, {recursive: true, force: true}) and fs.mkdirSync(baseDir, {recursive: true}) on /tmp/rolldown-<version>, which is outside the package directory. This is confined to a versioned tmp directory but still writes/removes files outside package scope.
Dynamic requires with computed/platform-specific specifiers
NPS-117A09F4C043
Numerous __require calls use dynamic platform/arch-derived specifiers (e.g., @rolldown/binding-linux-x64-gnu) and optional dependency loading. This is standard napi-rs binding loader behavior, but the pattern of resolving and loading many native .node binaries at import time is a supply-chain risk if any optional dependency is hijacked.
filesystem-read
NPS-558A02E78BA9
getDefaultDevRuntime reads runtime files via fs.readFileSync and fileURLToPath(import.meta.resolve(...)), but these paths are hardcoded package-internal runtime entries, not attacker-controlled or credential files.
filesystem-operations
NPS-F90165C3772C
A fsModule object exposes common async fs operations (readFile, writeFile, unlink, etc.) to plugin contexts. This is standard bundler plugin API surface for user-authored plugins, not autonomous package-install behavior.
import-time-execution
NPS-8ACEFC7C45A3
Top-level code includes Object.defineProperty patches on BindingMagicString.prototype and __decorate/lazyProp setup. These are local prototype enhancements within the package and do not perform network access, credential harvesting, or shell execution.
Dynamic string construction from runtime input
NPS-0BD94FDBC3F1
buildQueryRE() builds a RegExp from queryName using escapeRegExp; escapeRegExp is properly implemented to escape regex metacharacters, so regex injection is mitigated. formatTrackingQuery() concatenates runtime values into a URL query. No direct injection risk given upstream handling, but flagged for review.
Data URL code execution via Module.register
NPS-9BB06141E26F
loader_default is a data:text/javascript URL containing an embedded payload registered via Module.register() in a worker thread. While the payload is not obfuscated or encrypted (it is readable source), using a data URL as an ESM loader is an unconventional mechanism that evades normal file-based source review and could disguise malicious intent in modified versions.
File system manipulation outside package scope
NPS-086994C197C3
bundleTsConfig writes a generated bundle file (with inline sourcemap) into the directory containing the user's config file and deletes it afterward. loadNativeConfig also appends a timestamp query to the import URL to bypass module caching. This is expected for a build tool's config loader but does modify the user's working directory.
Files reviewed
| File | Verdict | What the reviewer saw |
|---|---|---|
| bin/cli.mjs | medium | The CLI entry point uses dynamic import and Node.js module compile cache APIs, which are legitimate but could be abused; no clear malicious behavior is evident. |
| dist/experimental-default-runtime.mjs | medium | This HMR dev runtime accepts unauthenticated WebSocket messages over plaintext ws:// and executes server-supplied module paths or script URLs, which could lead to remote code execution if the HMR server or network is compromised. |
| dist/parallel-plugin-worker.mjs | medium | The worker code dynamically imports modules from URLs provided via workerData and runs an async IIFE on import; while likely legitimate for a plugin system, the lack of validation on dynamic imports poses a moderate security risk if workerData is externally controllable. |
| dist/shared/binding-BY0qR5iS.mjs | medium | This is a standard napi-rs native binding loader for rolldown with legitimate platform-specific dynamic requires and a WebContainer fallback that downloads and installs a WASI binding package at runtime; no data exfiltration, credential harvesting, obfuscation, or backdoor patterns were detected, but runtime package installation and env-var-controlled native library loading are noteworthy supply-chain/risk surfaces. |
| dist/shared/dist-DKbukT1H.mjs | medium | The 'fresh-import' package purposefully registers ESM module hooks and performs dynamic imports with computed specifiers to re-evaluate modules in fresh graphs; while no overt malicious patterns (exfiltration, credential harvesting, backdoors, shells) are present, its powerful use of Module.registerHooks, data URL loaders, and dynamic imports warrants 'warning' risk for supply-chain review. |
| dist/shared/load-config-iYtRcbXn.mjs | medium | This is Rolldown's config loader that intentionally executes user-provided config files and bundles TypeScript configs, which is expected behavior for a build tool but involves dynamic code execution and temporary file writes. |
| dist/utils-index.mjs | medium | The file is a bundler-generated utility module for rolldown/oxc-parser AST visiting that is largely safe, with the only notable concern being a benign use of new Function for merging visitor callbacks. |
| dist/cli.mjs | safe | No malicious patterns detected; this is the legitimate Rolldown CLI bundler entrypoint with standard argument parsing and build logic. |
| dist/config.mjs | safe | The file only re-exports symbols from internal shared modules and contains no suspicious or malicious patterns. |
| dist/experimental-index.mjs | safe | No malicious patterns detected in this rolldown experimental API barrel file; all imports are internal relative modules and the logic handles bundler/dev-engine configuration without exfiltration, credential harvesting, obfuscation, or process spawning. |
| dist/experimental-runtime-base.mjs | safe | This file contains only standard esbuild/CommonJS/ESM interop helper functions and a base64-to-binary decoder with no network, filesystem, process, or dynamic code execution behavior. |
| dist/experimental-runtime.mjs | safe | No malicious patterns detected; this is a module runtime implementation with no network, filesystem, process, or dynamic code execution behavior. |
| dist/filter-index.mjs | safe | No malicious patterns detected; the file contains legitimate plugin filtering and filter-expression utilities for Rolldown/Vite with no data exfiltration, credential harvesting, obfuscation, dynamic execution, or process spawning. |
| dist/get-log-filter.mjs | safe | Cleared by Jev triage; no further analysis needed |
| dist/index.mjs | safe | No malicious patterns detected |
| dist/parallel-plugin.mjs | safe | No malicious patterns detected |
| dist/parse-ast-index.mjs | safe | No malicious patterns detected; the code is a straightforward AST parsing utility with no network, filesystem, process, or dynamic execution behavior. |
| dist/plugins-index.mjs | safe | No malicious patterns detected; the file only exports a benign Rolldown builtin replace plugin and an esm external require plugin with no network, filesystem, process, or dynamic code execution behavior. |
| dist/shared/bindingify-input-options-XrReX_BJ.mjs | safe | This is a legitimate Rolldown bundler internal module that wires plugin hooks, lazy properties, and binding APIs without any malicious exfiltration, credential access, shell spawning, or obfuscated payloads. |
| dist/shared/constructors-xEvVj3lN.mjs | safe | No malicious patterns detected; the code only defines Vite/Rolldown builtin plugin constructors with no network, filesystem, process, or dynamic execution behavior. |
| dist/shared/define-config-Demdg3_4.mjs | safe | No malicious patterns detected |
| dist/shared/error-C7pxws0W.mjs | safe | No malicious patterns detected; the file contains only sourcemap type helpers and error normalization utilities for a build tool. |
| dist/shared/logs-D6uA606S.mjs | safe | No malicious patterns detected; the file contains only local error/logging and code-frame utilities with no network, filesystem, process, or dynamic-execution behavior. |
| dist/shared/misc-DOSKtd97.mjs | safe | This file contains only standard utility functions (array coercion, promise detection, error throwers, noop, and path fragment validation) with no malicious patterns such as network calls, credential harvesting, obfuscation, or dynamic execution. |
| dist/shared/normalize-string-or-regex-F14uvr6D.mjs | safe | The code is a utility module for a Vite/Rolldown plugin system with no malicious patterns detected. |
Show 5 more files
| File | Verdict | What the reviewer saw |
|---|---|---|
| dist/shared/parse-WKtEKiA6.mjs | safe | The file is a JavaScript parser wrapper around a native Rust binding (oxc-parser) that parses JS/TS ASTs; no exfiltration, credential harvesting, obfuscation, network, process, or filesystem abuse patterns were detected. |
| dist/shared/prompt-CH6TK0bC.mjs | safe | This is a bundled consola prompt module that uses only standard Node.js APIs for terminal UI rendering with no malicious patterns detected. |
| dist/shared/resolve-tsconfig-DHwpIs5e.mjs | safe | No malicious patterns detected; the code is a legitimate TypeScript/JavaScript transformation wrapper that delegates to a native binding. |
| dist/shared/rolldown-CgWItHdG.mjs | safe | No malicious patterns detected; the code is a standard Rolldown bundler API wrapper with no data exfiltration, credential harvesting, obfuscation, or unauthorized system access. |
| dist/shared/watch-DUTFlQ6u.mjs | safe | This file is a legitimate bundler watcher module (Rolldown) that manages signal handling and file watch events without any malicious patterns. |
Scanned versions of rolldown
| Version | Verdict | Files | Scanned |
|---|---|---|---|
| 1.2.11 | Needs review | 30 | Oct 6, 2026 |
Frequently asked questions
Is rolldown safe to use?
No confirmed malware was found in rolldown@1.2.11, but the review flagged 2 high, 9 medium, 13 low severity findings for risky patterns worth checking before you rely on it.
Does rolldown contain malware?
No malware was identified in rolldown@1.2.11 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 rolldown checked?
Togoder Security downloaded the published npm package and had an AI model read its 30 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 rolldown 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 rolldown@1.2.11, cost nothing.