
Research
2025 Report: Destructive Malware in Open Source Packages
Destructive malware is rising across open source registries, using delays and kill switches to wipe code, break builds, and disrupt CI/CD.
import-in-the-middle
Advanced tools
import-in-the-middle is an module loading interceptor inspired by
require-in-the-middle, but
specifically for ESM modules. In fact, it can even modify modules after loading
time.
The API for
require-in-the-middle is followed as closely as possible as the default
export. There are lower-level addHook and removeHook exports available which
don't do any filtering of modules, and present the full file URL as a parameter
to the hook. See the Typescript definition file for detailed API docs.
You can modify anything exported from any given ESM or CJS module that's imported in ESM files, regardless of whether they're imported statically or dynamically.
import { Hook } from 'import-in-the-middle'
import { foo } from 'package-i-want-to-modify'
console.log(foo) // whatever that module exported
Hook(['package-i-want-to-modify'], (exported, name, baseDir) => {
// `exported` is effectively `import * as exported from ${url}`
exported.foo += 1
})
console.log(foo) // 1 more than whatever that module exported
This requires the use of an ESM loader hook, which can be added with the following command-line option.
node --loader=import-in-the-middle/hook.mjs my-app.mjs
Since --loader has been deprecated you can also register the loader hook programmatically via the Node
module.register()
API. However, for this to be able to hook non-dynamic imports, it needs to be
registered before your app code is evaluated via the --import command-line option.
my-loader.mjs
import * as module from 'module'
module.register('import-in-the-middle/hook.mjs', import.meta.url)
node --import=./my-loader.mjs ./my-code.mjs
When registering the loader hook programmatically, it's possible to pass a list
of modules, file URLs or regular expressions to either exclude or specifically
include which modules are intercepted. This is useful if a module is not
compatible with the loader hook.
Note: This feature is incompatible with the
{internals: true}Hook option
import * as module from 'module'
// Exclude intercepting a specific module by name
module.register('import-in-the-middle/hook.mjs', import.meta.url, {
data: { exclude: ['package-i-want-to-exclude'] }
})
// Only intercept a specific module by name
module.register('import-in-the-middle/hook.mjs', import.meta.url, {
data: { include: ['package-i-want-to-include'] }
})
Note: This feature is experimental and is incompatible with the
{internals: true}Hook option
If you are Hook'ing all modules before they are imported, for example in a
module loaded via the Node.js --import CLI argument, you can configure the
loader to intercept only modules that were specifically hooked.
instrument.mjs
import { register } from 'module'
import { Hook, createAddHookMessageChannel } from 'import-in-the-middle'
const { registerOptions, waitForAllMessagesAcknowledged } = createAddHookMessageChannel()
register('import-in-the-middle/hook.mjs', import.meta.url, registerOptions)
Hook(['fs'], (exported, name, baseDir) => {
// Instrument the fs module
})
// Ensure that the loader has acknowledged all the modules
// before we allow execution to continue
await waitForAllMessagesAcknowledged()
my-app.mjs
import * as fs from 'fs'
// fs will be instrumented!
fs.readFileSync('file.txt')
node --import=./instrument.mjs ./my-app.mjs
experimentalPatchInternals optionIt was found that import-in-the-middle didn't match the hooking behavior of require-in-the-middle in some cases:
https://github.com/nodejs/import-in-the-middle/issues/185
The experimentalPatchInternals option forces the loader to match the behavior of require-in-the-middle in these cases.
This option is experimental and may be removed or made the default in the future.
import { register } from 'module'
register('import-in-the-middle/hook.mjs', import.meta.url, {
data: { experimentalPatchInternals: true }
})
require are not affected at all.The 'require-in-the-middle' package provides similar functionality for intercepting and modifying module imports, but it is specifically designed for CommonJS modules using 'require'. It does not support ES modules.
The 'proxyquire' package allows you to override dependencies during testing. It is more focused on providing mock implementations for dependencies, whereas 'import-in-the-middle' is more general-purpose for intercepting and modifying imports.
The 'mock-require' package is used to mock Node.js modules during testing. It allows you to replace modules with mock implementations, similar to 'proxyquire', but it does not provide the same level of interception and modification capabilities as 'import-in-the-middle'.
FAQs
Intercept imports in Node.js
The npm package import-in-the-middle receives a total of 10,403,914 weekly downloads. As such, import-in-the-middle popularity was classified as popular.
We found that import-in-the-middle demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
Destructive malware is rising across open source registries, using delays and kill switches to wipe code, break builds, and disrupt CI/CD.

Security News
Socket CTO Ahmad Nassri shares practical AI coding techniques, tools, and team workflows, plus what still feels noisy and why shipping remains human-led.

Research
/Security News
A five-month operation turned 27 npm packages into durable hosting for browser-run lures that mimic document-sharing portals and Microsoft sign-in, targeting 25 organizations across manufacturing, industrial automation, plastics, and healthcare for credential theft.