event-emitter-testmetest@4.1.0
Malicious code in event-emitter-testmetest (npm)
Analysis
This package executes an obfuscated dropper at install time without declaring any lifecycle script. Its package.json has no preinstall/postinstall hook; instead binding.gyp contains a node-gyp command substitution — "sources":["<!(env node index.js >/dev/null 2>&1; echo stub.c)"] — which runs index.js during the install/rebuild step. index.js (1.67MB, single line) is wrapped in a Caesar-shift-2 decoder: eval((function(d,k){...})([char codes],2)). The decoded source imports node:zlib, gunzips a base64/hex-encoded second stage embedded in the file, imports node:child_process, and pipes that stage into a Bun interpreter: spawn([process.execPath,"run","-"],{stdio:"pipe"}) when a bun global is present, otherwise spawn(getBunPath(),["run","-"],{stdio:"pipe"}) after obtaining Bun, with a plain eval() of the decoded blob as fallback. The second stage is never shipped as a file — it is assembled in memory at install time, so the package's real payload is not visible in the tarball. The package name is a combosquat of the widely used `event-emitter` package (real name intact plus a "-testmetest" suffix), ships no README and no repository, and its only other file is the binding.gyp stub. No network endpoint is hardcoded in the decoded first stage; the C2/payload is delivered through the runtime-assembled second stage.
- analyzed by
- Leitwacht
- first seen
- Oct 21, 2026, 02:04 PM
- analyzed
- Oct 21, 2026, 02:07 PM
Related advisories
- event-emitter-testmetest@1.0.7 same package
- event-emitter-testmetest@1.0.6 same package
- event-emitter-testmetest@1.0.4 same package
- data-pipeline-testmetest@2.0.0
- stream-utils-testmetest@1.0.0
- data-pipeline-testmetest@2.0.1
- casamare@1.0.0
- @apollolibraryorg/dotenv@1.0.2
Independently detected by the Leitwacht supply-chain probe. IOCs are defanged. Published CC0. Think this is a mistake? See the dispute policy.