Togoder security

npm package security report

ts-node@10.9.2 security report

Risky patterns found that deserve a look.

Needs review Version 10.9.2 Files reviewed 50 Size 255.6 KB Scanned

Summary

Togoder Security scanned the npm package ts-node@10.9.2 on Oct 4, 2026. An AI review of 50 source files produced 7 medium, 21 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.

0
critical
0
high
7
medium
21
low

Findings 28

medium

Dynamic module resolution with external input

NPS-B74BA9E48017

The code implements a custom CommonJS loader that resolves module paths based on user-supplied package.json fields and request strings. While this mirrors Node.js internal behavior, the presence of custom resolution logic that reads and interprets package.json 'main', 'exports', and 'imports' fields could be abused if an attacker can control package.json contents (e.g., via a malicious dependency) to load unintended files. However, this is a standard pattern for TS-Node-like tools and not inherently malicious.

dist-raw/node-internal-modules-cjs-loader.js:180
medium

dynamic module loading with external input

NPS-7A2BD5D24621

The code implements an ES module resolver that dynamically constructs module paths and resolves specifiers from user input (e.g., package.json exports/imports fields, specifiers). While this is expected for a resolver, it could be abused if malicious package.json files are present, potentially leading to loading unintended modules.

dist-raw/node-internal-modules-esm-resolve.js
medium

dynamic import with computed input

NPS-DDC826B76E27

The function takes an arbitrary entryPointPath and calls import() on its file URL. If an attacker can control entryPointPath, this enables loading and executing arbitrary JavaScript modules from any path, potentially bypassing Module.runMain restrictions.

dist-raw/runmain-hack.js:8
medium

Encoded payload in command-line arguments

NPS-C9EF49B9448D

The module exports an argPrefix constant ('--brotli-base64-config=') and compress/decompress functions that serialize and deserialize arbitrary objects to/from base64-encoded Brotli data intended to be passed via process.argv. While the code itself does not perform any exfiltration, credential harvesting, or execution, it provides a generic mechanism for embedding opaque serialized configuration data into command-line arguments. This pattern can be abused by other parts of the package to pass hidden or obfuscated payloads through process argv, which is a common technique in malicious packages to smuggle data past casual inspection. The decompress function uses JSON.parse on untrusted input, which could be leveraged for prototype pollution or unexpected object injection if the parsed object is later merged or used unsafely.

dist/child/argv-payload.js:5
medium

Suppression of security-relevant warnings

NPS-1DDD73BA8EE3

The onWarning function specifically filters out ExperimentalWarning messages that match a regex for --loader or Custom ESM Loaders. This suppresses warnings that Node.js emits when using experimental ESM loader hooks. While this is a common technique to reduce noise, suppressing such warnings could hide the use of custom loaders that might be used to load malicious code or alter module resolution.

dist/child/child-require.js
medium

Module loading hook installation

NPS-DDA8B16F2073

The file installs custom CommonJS module resolution hooks by overriding Module._resolveFilename and Module._findPath. This behavior is typical of ts-node's experimental resolver and is gated behind tsNodeService.options.experimentalResolver, but monkeypatching Node's internal module loader is a sensitive operation that can alter how dependencies are resolved. If the tsNodeService is influenced by untrusted input, it could potentially redirect module resolution to attacker-controlled code.

dist/cjs-resolve-hooks.js:9
medium

Dynamic module loading / import-time side effect

NPS-BAAE871A199F

The file requires the parent module ('../') and immediately invokes its register() method at the top level. This means that importing this file triggers execution of arbitrary code defined in the parent package's register() function. While the current file itself contains no obvious malicious payload, the pattern of executing a register() function at import time is a common vector for side effects such as registering hooks, installing backdoors, or performing network/file operations. The actual behavior depends entirely on the implementation of register() in the parent module, which is not shown and should be audited.

register/index.js:1
low

Dynamic module loading

NPS-76A88418D2E1

Uses createRequire() and require() to dynamically load a module from the dist directory. While this pattern is commonly used in ESM/CJS interoperability layers, dynamic require() can be abused to load arbitrary or computed modules and bypass static analysis. The file imports a local package-relative path, which limits the immediate risk, but the pattern warrants review.

child-loader.mjs:4
low

TODO comment indicating unresolved design

NPS-7E9E7FD38CD8

The comment 'TODO why use require() here? I think we can just import' indicates the author is uncertain about the dynamic require usage. Unresolved dynamic loading patterns are a code smell and could hide future malicious changes if the required path is later altered.

child-loader.mjs:4
low

Use of internal Node.js primordials

NPS-DB04E2652ABA

The code imports internal Node.js primordials and internal bindings (e.g., node-primordials, node-internalBinding-fs). This is typical for tools that patch Node.js internals (like ts-node) but indicates deep integration that could break or be abused in future Node versions. Not malicious by itself.

dist-raw/node-internal-modules-cjs-loader.js:7
low

Top-level code execution on import

NPS-2F73AAE77AEB

The module executes top-level code (e.g., reading options, initializing caches) when imported. This is normal for a module loader but means any side effects (like reading environment options via getOptionValue) occur at import time. No malicious side effects observed.

dist-raw/node-internal-modules-cjs-loader.js:30
low

File system access and stat caching

NPS-4B4EBF5FB0E9

The code performs extensive file system operations (stat, realpathSync, readPackage) to resolve modules. This is expected for a module loader but could be leveraged for reconnaissance (probing file existence) if the attacker controls the request paths. No direct exfiltration or credential harvesting is present.

dist-raw/node-internal-modules-cjs-loader.js:50
low

Potential for path traversal via package.json fields

NPS-D006034372AC

The tryPackage function resolves the 'main' field of package.json to a file path without strict validation. If a malicious package.json contains a 'main' field like '../../etc/passwd', it could attempt to load arbitrary files. However, this is standard Node.js behavior and not a vulnerability introduced by this code. The code does not sanitize but relies on Node's resolution rules.

dist-raw/node-internal-modules-cjs-loader.js:130
low

file system access

NPS-1400FF7EC891

The code uses fs.statSync and fs.realpathSync to check file existence and resolve paths, including accessing node_modules directories and package.json files. This is typical for a module resolver, but excessive file system probing could be a concern if the input is untrusted.

dist-raw/node-internal-modules-esm-resolve.js
low

environment-dependent behavior

NPS-2757B2828C2E

The resolver uses process.versions.node and getOptionValue to adjust behavior based on Node.js version and command-line flags. This is standard, but it could be used to conditionally enable malicious behavior in other contexts.

dist-raw/node-internal-modules-esm-resolve.js
low

warning emission

NPS-609AC56D435E

The code emits deprecation warnings via process.emitWarning, which is not malicious but could be used to spam output.

dist-raw/node-internal-modules-esm-resolve.js
low

Dynamic module loading

NPS-A28C6F0B5D17

The code uses require('arg') to load an external dependency. While 'arg' is a legitimate argument parsing library, this introduces a supply chain risk if the dependency is compromised.

dist-raw/node-options.js:30
low

Environment variable access

NPS-2893037D233B

The code reads process.env.NODE_OPTIONS and process.env.NODE_PENDING_DEPRECATION, which is expected for a Node.js options parser but could be leveraged to influence runtime behavior if an attacker controls these environment variables.

dist-raw/node-options.js:44
low

child process spawning

NPS-8508D34934F0

The code spawns child processes via callInChild for ESM support. This is a documented feature of ts-node and not a backdoor or reverse shell.

dist/bin.js:38
low

legitimate dynamic code execution

NPS-84459502D551

The code uses require() and Module.runMain() for normal CLI operation, which is expected for a Node.js runtime tool like ts-node; no malicious eval or obfuscated payloads are present.

dist/bin.js:582
low

Encoded payload decoding

NPS-2EAC9CA824F3

The code reads a base64-encoded argument from process.argv[2] and decompresses it via decompress(). While this is a legitimate IPC mechanism used by ts-node to pass serialized state to child processes, encoded/decompressed payloads are commonly used in malware to hide intent and bypass static scanning. In this context the decoded data is used to reconstruct CLI state rather than execute hidden logic, but the pattern warrants attention.

dist/child/child-entrypoint.js:6
low

Process argument manipulation

NPS-92D3430F7763

The code rewrites process.argv[2] with a re-compressed payload when running as CLI, then proceeds to bootstrap via bin_1.bootstrap(state). This re-injects serialized state into subsequent child process invocations. If an attacker could control the initial payload (e.g., by influencing argv), the decompressed state would be trusted and used directly. No validation of the decompressed payload's schema or origin is performed.

dist/child/child-entrypoint.js:15
low

Direct manipulation of internal Node.js process events

NPS-817CAF1BF3B3

The code directly accesses and modifies the private _process._events.warning array/object instead of using the public API (process.on, process.removeListener). This is fragile, unsupported, and can break other listeners. It is not inherently malicious, but it is a code smell and could be used to silently suppress warnings that might alert a user to malicious behavior.

dist/child/child-require.js
low

Dynamic module loading via require

NPS-8A8D63CBAFB1

The code uses require('module') to import Node's built-in module system at runtime. While this is a legitimate use for accessing the loader internals, it indicates dynamic module loading behavior that should be considered within a broader supply-chain risk assessment.

dist/cjs-resolve-hooks.js:7
low

Dynamic module loading

NPS-33301E7A96BF

The file requires '../' (a relative parent module) and invokes its .register() method at the top level. This executes code immediately upon import and can load arbitrary transpilation plugins depending on the parent module's implementation. While this is the standard pattern for ts-node/register/transpile-only.js, it demonstrates runtime code execution and dynamic module resolution that could be abused if the parent package is compromised or resolved unexpectedly.

register/transpile-only.js:1
low

Top-level code execution on import

NPS-9F7693E21A53

The require('../') call and subsequent .register() invocation run automatically when this file is imported, with no guard. This is a common entrypoint pattern for register hooks, but it means simply requiring this module triggers behavior (transpiler registration) without explicit user action.

register/transpile-only.js:1
low

Import-time execution

NPS-1317570DCA12

The file executes code at import time by calling require('../').register(...). While this pattern is typical for library registration hooks, it does invoke the package's register function immediately upon loading, which could execute arbitrary behavior depending on the implementation of the required module.

register/type-check.js:1
low

Dynamic module loading

NPS-60809625E395

The use of require('../') resolves a relative parent module dynamically at runtime. This is standard Node.js behavior, but the parent module's register implementation is not shown and could contain further logic. No obfuscation, external network calls, credential harvesting, or shell execution is present in this specific file.

register/type-check.js:1

Files reviewed

FileVerdictWhat the reviewer saw
child-loader.mjs medium The file is a small ESM/CJS loader shim with no overt malicious behavior, but its use of dynamic require() for a dist module is a minor code-smell worth reviewing.
dist-raw/node-internal-modules-cjs-loader.js medium The code is a modified copy of Node.js internal CJS loader used by ts-node; it exhibits complex module resolution and file system access typical of such tools, with no clear malicious patterns like exfiltration or backdoors.
dist-raw/node-internal-modules-esm-resolve.js medium The code is a legitimate Node.js ES module resolver with no clear malicious intent, but it performs dynamic module resolution and file system access that could be abused if the environment or package.json files are compromised.
dist-raw/node-options.js medium The code appears to be a legitimate reimplementation of Node.js internal options parsing, with no clear malicious patterns, though it does access environment variables and dynamically load a dependency.
dist-raw/runmain-hack.js medium Uses dynamic import() with an externally supplied path, which could load and execute arbitrary code if the input is attacker-controlled.
dist/child/argv-payload.js medium The file contains a utility for encoding/decoding arbitrary objects into command-line arguments via Brotli+base64, which is not inherently malicious but enables obfuscated payload smuggling and should be reviewed in the context of how it is used elsewhere in the package.
dist/child/child-entrypoint.js medium This is a legitimate ts-node child-process entrypoint that decodes a base64 state payload from argv and bootstraps the CLI, but the encoded-payload pattern and unvalidated deserialization are worth noting even though no clear malicious behavior is present.
dist/child/child-require.js medium The code safely manipulates Node.js process warning events to suppress specific experimental loader warnings; while not malicious, it uses private internals and hides security-relevant warnings, warranting caution.
dist/cjs-resolve-hooks.js medium The file overrides Node.js internal CommonJS resolver functions (a gated, ts-node-style hook), which is legitimate but modifies module resolution behavior and warrants review of the calling context.
register/index.js medium Top-level execution of a register() function from a parent module may hide malicious side effects that are not visible in this file.
register/transpile-only.js medium This appears to be a legitimate ts-node-style register hook for transpile-only mode; the only concerns are the inherent top-level dynamic require and auto-registration, which are low-risk and expected for this package type.
register/type-check.js medium The file contains only a benign registration call with no overt malicious patterns, though it does execute code at import time via a relative require.
dist-raw/node-internal-constants.js safe Cleared by Jev triage; no further analysis needed
dist-raw/node-internal-errors.js safe Cleared by Jev triage; no further analysis needed
dist-raw/node-internal-modules-cjs-helpers.js safe No malicious patterns detected; the code is a legitimate copy of Node.js internal module helper for exposing built-in modules.
dist-raw/node-internal-modules-esm-get_format.js safe No malicious patterns detected; the code is a direct copy of Node.js internal ESM get_format logic with benign module format resolution.
dist-raw/node-internal-modules-package_json_reader.js safe No malicious patterns detected
dist-raw/node-internal-repl-await.js safe No malicious patterns detected; this is a legitimate copy of Node.js internal REPL await transformation logic.
dist-raw/node-internalBinding-fs.js safe Cleared by Jev triage; no further analysis needed
dist-raw/node-nativemodule.js safe Cleared by Jev triage; no further analysis needed
dist-raw/node-primordials.js safe Cleared by Jev triage; no further analysis needed
dist/bin-cwd.js safe No malicious patterns detected in this thin wrapper that delegates to ./bin with a cwd mode flag.
dist/bin-esm.js safe No malicious patterns detected
dist/bin-script-deprecated.js safe No malicious patterns detected; the file is a simple deprecation notice that delegates to a local module.
dist/bin-script.js safe No malicious patterns detected in the provided entry-point wrapper; it simply imports and invokes the package's main function.
Show 25 more files
FileVerdictWhat the reviewer saw
dist/bin-transpile.js safe No malicious patterns detected
dist/bin.js safe The code is the legitimate ts-node CLI entry point; no malicious patterns such as data exfiltration, credential harvesting, obfuscation, or backdoors were detected.
dist/child/child-loader.js safe This is a legitimate ESM loader child process module that proxies Node.js loader hooks; no malicious patterns detected.
dist/child/spawn-child.js safe This is a legitimate ts-node internal utility for spawning a child Node.js process with inherited stdio and signal forwarding, containing no malicious patterns.
dist/configuration.js safe No malicious patterns detected; the code is a legitimate ts-node configuration utility that reads and merges TypeScript config files without exfiltration, obfuscation, or suspicious process/network activity.
dist/esm.js safe No malicious patterns detected; the code is a legitimate ts-node ESM loader implementation.
dist/file-extensions.js safe No malicious patterns detected
dist/index.js safe No malicious patterns detected; the code is the legitimate ts-node runtime with expected compiler, resolver, and loader-hook behavior.
dist/module-type-classifier.js safe The file is a benign TypeScript module type classifier with no malicious patterns, network calls, code execution, or credential harvesting.
dist/node-module-type-classifier.js safe No malicious patterns detected
dist/repl.js safe No malicious patterns detected; the code implements a legitimate TypeScript REPL using vm.Script and Node's repl module as expected for ts-node.
dist/resolver-functions.js safe No malicious patterns detected; the code implements TypeScript module resolution functions without any data exfiltration, credential harvesting, obfuscation, or other suspicious behaviors.
dist/transpilers/swc.js safe No malicious patterns detected; the code is a legitimate SWC transpiler integration for ts-node that only performs dynamic module resolution of explicitly configured or default SWC compiler packages without exfiltration, obfuscation, or suspicious behavior.
dist/transpilers/types.js safe No malicious patterns detected
dist/ts-compiler-types.js safe No malicious patterns detected
dist/ts-internals.js safe No malicious patterns detected; the code is a TypeScript compiler utility library with no data exfiltration, credential harvesting, obfuscation, or suspicious behavior.
dist/ts-transpile-module.js safe No malicious patterns detected; the code is a legitimate TypeScript transpilation module wrapper with no external network, filesystem, or process manipulation.
dist/tsconfig-schema.js safe No malicious patterns detected; the file is a trivial CommonJS module marker with only a source map reference.
dist/tsconfigs.js safe No malicious patterns detected
dist/util.js safe No malicious patterns detected; the code contains standard utility functions for module resolution, version comparison, and caching without any exfiltration, credential harvesting, obfuscation, or suspicious behavior.
esm.mjs safe The file is a standard ESM compatibility shim that uses createRequire to load a local relative module and re-export its hooks; no malicious patterns detected.
esm/transpile-only.mjs safe No malicious patterns detected; the file only sets up ESM loader hooks via a local module using createRequire.
register/files.js safe The file only registers a 'files' option with the package's own dist module; no malicious patterns detected.
transpilers/swc-experimental.js safe Cleared by Jev triage; no further analysis needed
transpilers/swc.js safe Cleared by Jev triage; no further analysis needed

Frequently asked questions

Is ts-node safe to use?

No confirmed malware was found in ts-node@10.9.2, but the review flagged 7 medium, 21 low severity findings for risky patterns worth checking before you rely on it.

Does ts-node contain malware?

No malware was identified in ts-node@10.9.2 when Togoder Security scanned it on Oct 4, 2026. A new version can still introduce malicious code, so scan the exact versions in your lockfile.

How was ts-node checked?

Togoder Security downloaded the published npm package and had an AI model read its 50 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 ts-node 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 ts-node@10.9.2, cost nothing.

Related security reports