Feed
HighPublished 10 Jul 202625 packages · 25 versions

GitHub Advisory malware sweep — 25 npm packages (Epic Games / Unreal Engine internal-scope dependency-confusion cluster, LuminaryCloud, Reddit Voyager, nodemon family) taken down 2026-07-09 / 2026-07-10

Summary

On 2026-07-09 and 2026-07-10 GitHub's Advisory Database retired 25 CWE-506 Embedded Malicious Code npm advisories. The main story is a coordinated dependency-confusion burst against internal enterprise namespaces — Epic Games / Unreal Engine build tooling (robomerge, unreal-horde-dashboard, ue-jenkins-buildkite, ue-automation-scripts, epic-internal-tools), LuminaryCloud (@luminarycloudinternal/*), Reddit-style Voyager UI (voyager-web, searchresults), plus workspace/microsite scopes — all replaced by npm Security within a 12-minute window on 2026-07-10 02:57–03:10 UTC. A smaller tail of nodemon-* / chai-redirection / paperclip-adapter-helpers typosquats and 2026-07-09 throwaways (none123s, tslint-conf) rounds out the sweep.

dependency-confusiontyposquatcredential-theft
Detected by
GitHub Advisory Database · npm Security
Also known as
2026-07-09 GHSA npm sweep · 2026-07-10 GHSA npm sweep · Epic Games dep-confusion burst
Ecosystems
npm
Packages tracked
25

What happened

Between 2026-07-09 and 2026-07-10 GitHub's Advisory Database published 25 CWE-506 (Embedded Malicious Code) advisories against npm packages. Every record uses the standard "any computer that has this package installed or running should be considered fully compromised — rotate all secrets from a different computer" boilerplate. No payload write-ups accompany the GHSA texts, so defenders should treat install-time behavior as unanalyzed and assume worst case for any host that resolved these names.

The defining feature of this sweep — unlike the pure-typosquat runs of 2026-07-06, 2026-07-07, and 2026-07-08 — is that the majority of the 20 packages taken down on 2026-07-10 are dependency-confusion attempts against named enterprise internal namespaces, published and replaced within a tight 12-minute window (02:57–03:10 UTC).

Cluster 1 — Epic Games / Unreal Engine internal build-tooling cluster (5 packages)

robomerge, unreal-horde-dashboard, ue-jenkins-buildkite, ue-automation-scripts, epic-internal-tools. All five were replaced with 0.0.1-security between 2026-07-10 03:01:55 and 03:02:15 UTC — a 20-second replacement burst indicating the whole cluster was reported and taken down as a unit.

The naming space is not random — it directly mirrors Epic Games' public documentation for their internal build automation:

  • Robomerge is Epic's Perforce-based automated code merge system, documented publicly at dev.epicgames.com.
  • Horde is Epic's CI/build orchestration platform, documented for Unreal Engine licensees.
  • UE-Jenkins-Buildkite and UE-Automation-Scripts match Epic's Unreal Engine automation naming conventions.
  • Epic-Internal-Tools is the most on-the-nose slug — a generic catch-all internal namespace.

This is a canonical Alex Birsan-style dependency-confusion attack. The operator has clearly enumerated Epic Games' public build-tooling documentation and registered every plausible internal package name. Any Epic Games team or Unreal Engine licensee running an internal npm registry — with the fall-through to the public registry misconfigured — would have silently pulled these malicious versions on the next npm install.

Cluster 2 — LuminaryCloud internal-scope cluster (2 packages)

@luminarycloudinternal/lcvis-st (replaced 2026-07-10 03:10:00 UTC), @luminarycloudinternal/frodo (replaced 2026-07-10 03:09:51 UTC). LuminaryCloud is a physics-simulation SaaS company (founded 2020, acquired attention in the CFD / mesh-simulation space). The @luminarycloudinternal scope is not a legitimate public npm scope — a scope-prefixed name of this shape is the strongest possible signal of a dependency-confusion attempt, since scoped packages resolve exactly against the scope namespace.

Same operator playbook as the Epic Games cluster: enumerate a target org, guess plausible internal package names under a shared scope, publish squats at a version high enough to win the resolver race against internal releases. lcvis-st reads like a "Luminary Cloud Visualization Streaming" module; frodo is a common internal code-name.

Cluster 3 — Reddit-adjacent Voyager UI cluster (2 packages)

voyager-web (replaced 2026-07-10 03:00:04 UTC), searchresults (replaced 2026-07-10 02:59:58 UTC). "Voyager" is Reddit's React-based frontend framework, the successor to the classic reddit.com "Old Reddit" stack. The voyager-web name is a highly plausible internal package name for Reddit's web-app codebase; searchresults is a generic-but-plausible internal helper for a search UI component.

Both published within 10 seconds of each other and replaced together — same operator, same targeted enumeration approach as the Epic cluster.

Cluster 4 — Generic microsite / workspace scopes (3 packages)

@businessapp-microsites/apis (replaced 2026-07-10 02:58:14 UTC), workspace-scripts (02:58:01 UTC), workspace-lint (02:57:56 UTC). All three published in a 20-second window immediately before the Voyager cluster. The @businessapp-microsites scope pattern matches enterprise CMS/microsite tooling (a common naming convention for multi-tenant SaaS platforms). workspace-scripts and workspace-lint are generic monorepo helper names — plausible under @your-org/workspace-scripts, and if an internal npm mirror is misconfigured they could resolve unscoped against the public registry.

Cluster 5 — nodemon typosquat family (3 packages)

nodemon-patch (2026-07-10 02:54:57 UTC), nodemon-gulp (2026-07-10 02:46:28 UTC), nodemon-sudo (2026-07-09 12:34:15 UTC). Direct typosquats of nodemon, one of the top-100-installed dev packages on npm (~10M weekly downloads). The nodemon-<verb> pattern targets developers who assume a companion helper exists — canonical nodemon configuration is done via nodemon.json or CLI flags, and there are no first-party sidecar packages.

Cluster 6 — Chai matcher continuation

chai-redirection (replaced 2026-07-10 02:57:03 UTC). Direct continuation of the Chai matcher-squat theme from the 2026-07-06 chai-as-* cluster and 2026-07-07 chai-sdk / chai-spycore / chai-chain-dom cluster. The chai-<matcher-name> pattern targets developers extending Chai assertions with a plausible-sounding matcher name.

Cluster 7 — Miscellaneous typosquats and throwaways

  • paperclip-adapter-helpers (2026-07-10 02:36 UTC) — Paperclip framework typosquat; the canonical asset-uploader lib is Rails-side paperclip (Ruby), no first-party JS.
  • nodepack-daemon (2026-07-10 02:44 UTC) — nodepack squat.
  • crypto-promiser (2026-07-10 02:42 UTC) — Node.js crypto helper squat; the canonical lib is the built-in crypto module or node:crypto.
  • vps-new-manager (2026-07-10 02:36 UTC) — Generic VPS management tool squat.
  • cursed-ecto-d3ab00 (2026-07-10 03:08 UTC) — Elixir Ecto ORM squat with a random 6-hex-char suffix (d3ab00). The suffix pattern indicates an attacker-generated random slug, likely to evade takedown detection by not registering as a "sensible" name.
  • txs-builder-lib (2026-07-09 14:38 UTC) — Blockchain transaction-builder squat; targets any Web3-adjacent naming space.
  • tslint-conf (2026-07-09 12:34 UTC) — TSLint config squat. TSLint has been officially deprecated since 2019 in favor of ESLint; anyone still resolving TSLint packages is on legacy code.
  • none123s (2026-07-09 14:44 UTC) — Throwaway name with no obvious target.
  • @kl-starfish/test-01 (2026-07-09 22:08 UTC) — Throwaway scoped test package. Notable because as of the 2026-07-10 03:00 UTC replacement burst, this one was NOT replaced (still resolves to 2.0.0 on the registry) — GHSA classification but no npm-side yank yet.

Contrast with recent sweeps

| Date | Packages | Notes | |---|---|---| | 2026-07-02 | 9 | Tailwind + db-* cluster | | 2026-07-03 | 14 | TypeScript / API family + @sql-* scopes | | 2026-07-06 | ~155 | Largest 2026 sweep | | 2026-07-07 | ~65 | AI-SDK typosquats + Solana base58 | | 2026-07-08 | ~20 | Claude-Code typosquat cluster | | 2026-07-09 / 2026-07-10 | 25 | Epic Games / LuminaryCloud / Voyager dep-confusion + nodemon family |

The running July 1–10 npm-malware retirement count is ~295 packages across 8 GHSA sweeps — a step-change in the platform's take-down cadence.

Registry state and version notes

Every package except @kl-starfish/test-01 now resolves to a 0.0.1-security holding tarball owned by npm Security. Because the security replacement wipes the historical version list from the public registry response and OSV was unreachable at ingest time, the exact pre-replacement malicious version numbers for each package are not fully recoverable from primary sources. The version list below records the plausible dep-confusion version (99.9.9, the observed convention across the 2026-06-29 internal-scope cluster and Sonatype's 176-package campaign) for the dep-confusion cluster and a common 1.0.0 placeholder for the typosquats. Historical version tarballs may remain fetchable from the CDN for 24–72 hours after the security replacement lands and should be treated as live malware in any lockfile hit — regardless of exact version.

Affected packages (25)

  • npm@businessapp-microsites/apis
    99.9.9
  • npm@kl-starfish/test-01
    2.0.0
  • npm@luminarycloudinternal/frodo
    99.9.9
  • npm@luminarycloudinternal/lcvis-st
    99.9.9
  • npmchai-redirection
    1.0.0
  • npmcrypto-promiser
    1.0.0
  • npmcursed-ecto-d3ab00
    1.0.0
  • npmepic-internal-tools
    99.9.9
  • npmnodemon-gulp
    1.0.0
  • npmnodemon-patch
    1.0.0
  • npmnodemon-sudo
    1.0.0
  • npmnodepack-daemon
    1.0.0
  • npmnone123s
    1.0.0
  • npmpaperclip-adapter-helpers
    1.0.0
  • npmrobomerge
    99.9.9
  • npmsearchresults
    99.9.9
  • npmtslint-conf
    1.0.0
  • npmtxs-builder-lib
    1.0.0
  • npmue-automation-scripts
    99.9.9
  • npmue-jenkins-buildkite
    99.9.9
  • npmunreal-horde-dashboard
    99.9.9
  • npmvoyager-web
    99.9.9
  • npmvps-new-manager
    1.0.0
  • npmworkspace-lint
    99.9.9
  • npmworkspace-scripts
    99.9.9

Impact

  • Any host that installed any of the 25 packages listed below should be treated as fully compromised — every GHSA record uses the boilerplate CWE-506 "rotate all secrets from a different computer" language, and no patched version exists for any of them
  • Epic Games / Unreal Engine internal-scope cluster (5 packages: robomerge, unreal-horde-dashboard, ue-jenkins-buildkite, ue-automation-scripts, epic-internal-tools) — the naming space directly matches Epic's public documentation for their Perforce merge automation (Robomerge), Horde build system, and their internal Jenkins/Buildkite pipelines. This is a classic Alex Birsan-style dependency-confusion attempt: any Epic Games or Unreal Engine licensee running an internal npm registry with a package of these names would silently pull the public malicious version on the next resolver run
  • LuminaryCloud internal-scope cluster (2 packages: @luminarycloudinternal/lcvis-st, @luminarycloudinternal/frodo) — LuminaryCloud is a physics-simulation SaaS provider; the @luminarycloudinternal scope is not a legitimate public scope. Anyone at LuminaryCloud running a private registry mirror with a package under @luminarycloudinternal/* would have resolved the malicious public version if the mirror was misconfigured
  • Reddit-adjacent Voyager cluster (2 packages: voyager-web, searchresults) — "Voyager" is Reddit's in-progress React-based frontend framework (successor to the classic reddit.com stack); searchresults is a plausible internal helper name. Both published within 10 seconds of each other at 2026-07-10 03:00 UTC and taken down together
  • Generic microsite/workspace cluster (3 packages: @businessapp-microsites/apis, workspace-scripts, workspace-lint) — the @businessapp-microsites scope pattern matches enterprise CMS/microsite tooling naming; workspace-scripts and workspace-lint are common monorepo helper names
  • nodemon typosquat family (3 packages: nodemon-patch, nodemon-gulp, nodemon-sudo) — nodemon is one of the most-installed dev-time packages on npm (~10M weekly downloads). The nodemon-<verb> pattern targets developers who add nodemon plus a companion package. The canonical companion pattern is nodemon.json config or --exec flags, NOT sidecar packages
  • Miscellaneous typosquats and throwawayschai-redirection (Chai matcher squat continuation from the 2026-07-06 and 2026-07-07 chai cluster), paperclip-adapter-helpers (Paperclip framework typosquat), nodepack-daemon (nodepack squat), crypto-promiser (Node crypto helper squat), vps-new-manager (server-tooling squat), cursed-ecto-d3ab00 (Elixir Ecto ORM squat with a random 6-hex-char suffix — attacker-generated random-looking slug), txs-builder-lib (blockchain transaction-builder squat), tslint-conf (deprecated TSLint config squat), none123s (throwaway name), @kl-starfish/test-01 (throwaway scoped test)
  • No payload write-up accompanies the GHSA texts — defenders should treat install-time behavior as unanalyzed and assume worst case for any host that resolved these names. Combined with the 2026-07-08 sweep (~20 packages), 2026-07-07 sweep (~65 packages) and 2026-07-06 sweep (~155 packages), the running July 1–10 npm-malware retirement count is ~295 packages across 8 GHSA sweeps

What to do

  1. 1Grep every lockfile (package-lock.json, yarn.lock, pnpm-lock.yaml) for each name in the packages map below. Any match is a supply-chain incident: rotate every credential the build runner could reach and re-image the build host
  2. 2If you build with Unreal Engine or work at Epic Games: audit every internal Node.js project for imports of robomerge, unreal-horde-dashboard, ue-jenkins-buildkite, ue-automation-scripts, or epic-internal-tools. These are dependency-confusion squats against your build-automation tooling. If your internal npm registry mirror was ever configured to fall through to the public registry, one of these could have resolved silently. Register the equivalent names as stubs on the public npm registry to prevent future squats, and route internal names via .npmrc scope pinning
  3. 3If you work at LuminaryCloud: any dependency under @luminarycloudinternal/* in a lockfile is malware. Rotate every credential reachable from any build host that ever resolved this scope. Register the @luminarycloudinternal scope on the public npm registry as a defensive stub
  4. 4If your build ever resolved voyager-web or searchresults: audit whether an internal package of the same name should have won the resolver race. The Reddit "Voyager" project name may not be the actual target — the operator may have enumerated public Reddit docs and guessed at internal names
  5. 5For the nodemon-* cluster (nodemon-patch, nodemon-gulp, nodemon-sudo) — the canonical package is nodemon. There is no first-party nodemon companion package on npm; configuration is done via nodemon.json or CLI flags. Any nodemon sidecar in your lockfile should be reviewed
  6. 6For chai-redirection, paperclip-adapter-helpers, nodepack-daemon, crypto-promiser, vps-new-manager, cursed-ecto-d3ab00, txs-builder-lib, tslint-conf, none123s, or @kl-starfish/test-01 — these are typosquats/throwaways with no legitimate parent. Any lockfile match should be treated as a compromise and the build host re-imaged
  7. 7Register every internal @scope you use on the public npm registry (even as a stub) so a future dependency-confusion squat under the same scope cannot resolve. Pin your registry: use .npmrc to route scoped names to your internal mirror only (e.g. @luminarycloudinternal:registry=https://internal/), so the public-registry path is never queried
  8. 8Verify none of the 25 listed packages still resolves via your private mirror — internal Artifactory / Nexus / Verdaccio instances routinely cache tarballs and will keep serving the malicious versions after the public yank

References

npm-2026-07-10-ghsa-malware-sweep