Summary
Togoder Security scanned the npm package jiti@2.7.0 on Oct 6, 2026. An AI review of 7 source files produced 8 medium, 12 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 20
Dynamic import with computed path
NPS-A75858848440
The script dynamically imports a module using a relative path ('./jiti.cjs') and later dynamically imports a user-supplied script via jiti.import(resolved). While typical for a CLI tool, dynamic imports based on user input can pose a risk if the resolved path is not properly validated, potentially leading to arbitrary code execution.
Arbitrary code execution via module hook
NPS-A7EA70FFD422
The exported resolve/load hooks intercept all non-builtin, non-.mjs/.cjs module loads and transpile/execute them through the jiti runtime, including JSON modules converted to executable code (export default/module.exports). This allows code from any resolved file to run at import time.
Dynamic code execution
NPS-B0FB75ACE841
The loader uses jiti.transform to transpile arbitrary source files, which effectively evaluates/executes untrusted code during module loading. This is the intended behavior of a runtime transpiler but represents a code execution vector if a malicious module is resolved.
Environment access via import.meta.resolve
NPS-9B289770378E
jiti.esmResolve uses import.meta.resolve with a parent URL, which can resolve modules relative to arbitrary paths. Combined with dynamic import, this could be used to load modules from outside the intended scope if an attacker controls the id or parentURL. However, this is standard ESM resolution behavior and not malicious on its own.
Dynamic import with computed input
NPS-7E23E2C5E434
The jiti.import function constructs module specifiers dynamically from user-provided 'id', suffix, and extension values, then calls dynamic import(resolved). While this is expected behavior for a module loader, it allows loading arbitrary modules based on external input. This is a potential vector if untrusted input is passed to jiti.import, but it is the intended functionality of the package and not inherently malicious.
Dynamic module registration at import time
NPS-E0107379E763
The file uses top-level code with node:module register() to install a custom ESM loader hook from './jiti-hooks.mjs' at import time. This executes automatically whenever the module is imported and changes how subsequent modules are resolved/loaded. While this is a common legitimate pattern for runtime TypeScript/ESM loaders, custom loaders can intercept and alter module resolution and execution, so it warrants review of jiti-hooks.mjs.
Dynamic module loading with computed input
NPS-B8C752B94C66
The nativeImport helper calls the native import() function with a caller-supplied id. While this file only re-exports a factory function (createJiti) and does not itself trigger a load, the underlying _createJiti will resolve and execute modules based on runtime input. This is the intended behavior of a jiti runtime transpiler/loader, but it means any consumer passing attacker-controlled specifiers could cause arbitrary code execution.
Dynamic module loading with external input
NPS-E6E61F5E849A
The function createJiti accepts a dynamic 'id' parameter and passes it to _createJiti for module resolution/loading. Additionally, nativeImport dynamically imports modules by id. While this is the intended purpose of a JITI (Just-In-Time Importer) library, it means the package can load arbitrary modules based on user input, which could be abused if inputs are not properly validated.
Module resolution from user input
NPS-ACA6F2631C45
The script resolves a user-provided script path using jiti.resolve and then imports it. If an attacker can control the script argument, they could potentially execute arbitrary code. However, this is the intended functionality of a CLI tool, so the risk is inherent to the tool's purpose.
Dynamic import / module loading with computed input
NPS-4E85DF3B85CD
createJiti() is invoked with the current filename, and jiti.import is passed as jitiImport into generated modules. Resolved specifiers from external input are passed to jiti.esmResolve, enabling dynamic module resolution based on runtime input.
File system access
NPS-B0610DF7C378
readFile is used on arbitrary resolved file paths and recursively walks parent directories to locate package.json, reading file contents and parsing JSON. This is expected for a loader but accesses files outside the immediate package scope.
Code generation / string interpolation into executable source
NPS-8F2CAEF1CF82
_wrapSource constructs a JavaScript module string via template literal interpolation of the transpiled source and filename, then returns it as a module format for execution. While not eval() literally, it is dynamic code construction executed by the ESM loader.
Potential bug: undefined variable reference
NPS-12F9AC3B6A36
In normalizeParentURL, the check 'typeof filename !== "string"' references an undeclared variable 'filename' instead of the function parameter 'input'. If 'filename' is not defined in the enclosing scope, this will throw a ReferenceError at runtime. This appears to be a bug, not a security issue, but could lead to unexpected behavior.
Dynamic import of local module
NPS-1AF5CAFE9C4A
register('./jiti-hooks.mjs', import.meta.url, {}) loads a relative module dynamically via Node's loader mechanism. The target is local and relative to import.meta.url rather than a computed external input, which reduces risk, but the actual behavior depends entirely on the contents of jiti-hooks.mjs.
Top-level execution on import
NPS-86215B5210AD
Importing this module immediately creates a createRequire reference and binds a Babel transform (_babelTransform) at module scope. This is not an install-time script and does not perform I/O by itself, but it does pull in ../dist/babel.cjs and ../dist/jiti.cjs, both of which execute at import time. These files are outside the scope of this snippet and would need separate review.
Transform function injection surface
NPS-9391DAB44494
createJiti replaces opts.transform with _babelTransform whenever the caller does not supply one. Any caller who can influence opts can instead supply an arbitrary transform function, which jiti will invoke on module source. This is a legitimate configuration point, but it is a code-execution vector if opts is ever built from untrusted input.
Error handling rethrow
NPS-778DBBF496DB
onError simply rethrows errors. This is benign and does not introduce security concerns.
Lazy require of internal module
NPS-B758FEDDDE66
lazyTransform lazily requires '../dist/babel.cjs' at runtime. This is a standard pattern to avoid loading heavy dependencies until needed, but it means code execution occurs upon first use. The referenced file is part of the package's own dist directory and is not suspicious per se.
Dynamic import with computed input
NPS-77CC5C3A22A3
The nativeImport function uses a dynamic import with the variable 'id' passed from external callers. This could allow loading arbitrary modules if an attacker can control the id value. In the context of Jiti, this is expected behavior for a runtime module loader, but it is a potential vector if the input is not properly validated by callers.
Lazy loading of native addon/transformer
NPS-30A5AE524C9B
The lazyTransform function uses createRequire to dynamically load '../dist/babel.cjs' at runtime when no transform option is provided. While common in Jiti for lazy-loading Babel, this pattern can be abused if the package is compromised to load malicious code. The path is relative and within the package, but the lazy loading means it isn't evaluated at import time.
Files reviewed
| File | Verdict | What the reviewer saw |
|---|---|---|
| lib/jiti-cli.mjs | medium | The code is a legitimate CLI tool (jiti) with expected dynamic import behavior, but the use of computed dynamic imports from user input carries an inherent risk of arbitrary code execution if the script path is untrusted. |
| lib/jiti-hooks.mjs | medium | This is a legitimate jiti ESM loader hook that intentionally transpiles and executes arbitrary module source at import time, which is expected for its purpose but constitutes an inherent dynamic code execution surface with no evidence of exfiltration, credential harvesting, or backdoors. |
| lib/jiti-native.mjs | medium | The file implements a native ESM-only version of the jiti module loader with dynamic imports and resolution based on caller-provided identifiers; no overtly malicious patterns such as exfiltration, credential harvesting, obfuscation, or process spawning were found, but the dynamic import capability and a potential undefined-variable bug warrant caution. |
| lib/jiti-register.mjs | medium | No direct malicious behavior is present in this file, but it installs a custom module loader hook at import time, so the referenced jiti-hooks.mjs must be reviewed to fully assess risk. |
| lib/jiti-static.mjs | medium | No direct malicious behavior in this file, but it exposes a dynamic import/transform loader whose safety depends entirely on the caller-controlled inputs and the separate dist/jiti.cjs and dist/babel.cjs bundles. |
| lib/jiti.cjs | medium | The code appears to be a legitimate JITI (Just-In-Time Importer) wrapper with no obvious malicious patterns, though its inherent dynamic module loading capability warrants caution. |
| lib/jiti.mjs | medium | No clear malicious intent detected; the code uses dynamic imports and lazy loading typical of a runtime module loader like Jiti, but these patterns warrant caution if the package is compromised. |
Scanned versions of jiti
| Version | Verdict | Files | Scanned |
|---|---|---|---|
| 2.7.0 | Needs review | 7 | Oct 6, 2026 |
Frequently asked questions
Is jiti safe to use?
No confirmed malware was found in jiti@2.7.0, but the review flagged 8 medium, 12 low severity findings for risky patterns worth checking before you rely on it.
Does jiti contain malware?
No malware was identified in jiti@2.7.0 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 jiti checked?
Togoder Security downloaded the published npm package and had an AI model read its 7 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 jiti 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 jiti@2.7.0, cost nothing.