GitHub Advisory npm malware sweep, 21 July 2026

HighAdvisory sweepnpm

On 2026-07-21 GitHub's Advisory Database retired six CWE-506 npm malware advisories. Highlights: a 3-package streak-* habit-tracker cluster (streak-daycount, streak-calendar, svelte-streaks) published within a 56-minute window on 2026-07-21 and security-replaced 8 hours later, a @apexfdn/apex 33-version 2.5-week dependency-confusion burst (1.0.0 → 1.0.32), and a nolby 4-version 4-hour rapid-burst.

Published 21 Jul 2026

At a glancenpm-2026-07-21-ghsa-malware-sweep
6
Packages tracked43 malicious versions

Every version named by the advisory is in the scanner, so a lockfile check finds it directly.

Severity
High
Type
Advisory sweep
Published
21 Jul 2026
Ecosystems
npm
Detected by
GitHub Advisory Database, npm Security
Also known as
2026-07-21 GHSA npm sweep, streak-* habit-tracker cluster, @apexfdn/apex dep-confusion burst

Advisory sweep. A dated batch of GitHub Advisory Database malware entries collected together. A sweep mixes kinds - typosquats, dependency-confusion probes, boilerplate takedowns with no published analysis, and occasionally real payloads - and its severity reflects the worst confirmed item, not the batch as a whole.

What happened

The full picture

On 2026-07-21 GitHub's Advisory Database published six CWE-506 (Embedded Malicious Code) advisories against npm packages. All six records use the standard "any computer that has this package installed or running should be considered fully compromised - rotate all secrets from a different computer" boilerplate.

Two additional 2026-07-21 GHSA npm advisories - chai-as-reddit (GHSA-vc32-h28h-pmhm) and chai-leaf (GHSA-m3c7-2j38-rjh7) - are not covered here. They are the DPRK-linked jsonspack operator's continued chai-as-* typosquat campaign and are catalogued under npm-2026-06-27-chai-as-persisted-jsonspack (updated 2026-07-21 for these two additions).

Cluster 1 - streak-* habit-tracker cluster (3 packages)

PackageVersionsPublish window (UTC)npm security-replace (UTC)
streak-daycount1.0.02026-07-21 14:56:042026-07-21 23:16:40
svelte-streaks1.0.0 → 1.0.22026-07-21 14:56:14 → 15:52:492026-07-21 23:17:02
streak-calendar1.0.0 → 1.0.12026-07-21 15:17:37 → 15:52:372026-07-21 23:16:35

All three packages were published within a 56-minute window (14:56:04 → 15:52:49 UTC) and security-replaced within a 27-second window eight hours later (23:16:35 → 23:17:02 UTC). The shared "streak" habit-tracker theme (day-count / calendar / Svelte streak widget) and near-identical publish→take-down cadence strongly indicate a single publisher exercising a specific target scope - likely a habit-tracker app product namespace where an internal team publishes streak-* component libraries.

Cluster 2 - @apexfdn/apex 33-version dependency-confusion burst (1 package)

PackageVersionsPublish window (UTC)npm security-replace (UTC)
@apexfdn/apex1.0.0 → 1.0.32 (33 versions)2026-07-05 → 2026-07-212026-07-21

Thirty-three versions 1.0.0 through 1.0.32 published across 17 days from 2026-07-05 to 2026-07-21, then npm-security-replaced 2026-07-21 UTC. The sustained multi-day publish cadence at monotonically incrementing patch levels fits a classic dependency-confusion pattern where the operator keeps publishing higher patches to survive a specific resolver behavior.

The @apexfdn scope is unregistered on the public npm registry - the scope name reads as "Apex Foundation", a typical internal-scope pattern where an organization publishes @apexfdn/* packages to a private registry (Artifactory, Nexus, Verdaccio, GitHub Packages) and relies on .npmrc scope routing to keep them internal. Any lockfile pin on @apexfdn/apex indicates the resolver picked the public malicious tarball over the intended private one - a resolver misconfiguration that leaks the internal scope name to the public registry.

Cluster 3 - nolby 4-version rapid-burst (1 package)

PackageVersionsPublish window (UTC)npm security-replace (UTC)
nolby1.0.0 → 1.0.3 (4 versions)2026-07-21 05:42:46 → 09:27:352026-07-21 17:00:39

Four versions published within 3 hours 45 minutes on 2026-07-21, then security-replaced 7.5 hours after the final version pushed. The tight same-day version-bump cadence, plus the choice of a short unregistered name, is characteristic of a single operator iterating on a payload while probing a specific resolver behavior.

Cluster 4 - veskra singleton (1 package)

PackageVersionsPublish window (UTC)npm security-replace (UTC)
veskra(original versions no longer resolvable)pre-2026-07-212026-07-21 17:00:45

The pre-existing veskra name was directly npm-security-replaced 2026-07-21 17:00:45 UTC with no visible original version metadata still in the registry - the original tarball(s) were pulled before the security-holder replacement, and only the sentinel 0.0.1-security tarball remains publicly resolvable. Any lockfile that pinned veskra at any non-security version is affected - no way to enumerate the original version list from the public registry after this pattern of removal.

Registry state

All 6 packages were npm-security-replaced (0.0.1-security sentinel tarball at latest dist-tag). Original version tarballs are no longer resolvable on the public registry, but private registry mirrors that cached the tarballs during the publish window WILL keep serving the original versions after the public yank - any lockfile hit must be treated as actionable regardless of what the public registry currently returns.

dependency-confusioncredential-theft
Affected packages

6 packages 43 versions

These are usually pulled in as transitive dependencies rather than installed directly. Check your whole tree at once. It runs in your browser and nothing is uploaded.

Impact

What it does if you installed it

  • Any host that installed any of the packages 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
  • *`streak- habit-tracker cluster** (3 packages): streak-daycount@1.0.0 (published 2026-07-21 14:56:04 UTC), streak-calendar@1.0.0/1.0.1 (2026-07-21 15:17:37 → 15:52:37 UTC), and svelte-streaks@1.0.0/1.0.1/1.0.2 (2026-07-21 14:56:14 → 15:52:49 UTC) were all published within a 56-minute window and security-replaced with 0.0.1-security` sentinel tarballs in a tight 27-second window at 2026-07-21 23:16:35 → 23:17:02 UTC - a coordinated single-actor pattern. The shared "streak" habit-tracker theme (day-count / calendar / Svelte streak widget) and near-identical publish→take-down cadence indicate a single publisher exercising a specific target scope
  • @apexfdn/apex 33-version dependency-confusion burst (1 package): 33 versions 1.0.0 → 1.0.32 published across 17 days from 2026-07-05 → 2026-07-21, then npm-security-replaced 2026-07-21 UTC. The @apexfdn scope name is unregistered on public npm - the sustained multi-day publish cadence at monotonically incrementing patch levels fits a classic dependency-confusion pattern where the operator keeps publishing higher patches to survive a specific resolver behavior (some resolvers cache-invalidate on version bump, others don't). The scope apexfdn reads as "Apex Foundation" - a likely internal-registry scope name at a specific organisation. Any lockfile pin on @apexfdn/apex indicates the resolver picked the public malicious tarball over the intended private one
  • nolby 4-version rapid-burst (1 package): 4 versions 1.0.0 → 1.0.3 published within 3h 45min on 2026-07-21 (05:42:46 → 09:27:35 UTC), then security-replaced 2026-07-21 17:00:39 UTC. The tight version-bump cadence in the same day, plus the choice of a short unregistered name, is characteristic of a single operator iterating on a payload while probing a specific resolver behavior
  • veskra singleton (1 package): the pre-existing veskra name was directly npm-security-replaced 2026-07-21 17:00:45 UTC with no visible original version metadata still in the registry - indicating the original tarball was pulled before the security-holder replacement, and only the sentinel tarball remains publicly resolvable. Any lockfile that pinned veskra at any version prior to 0.0.1-security is affected
  • None of the 6 packages have surviving version tarballs on the public npm registry - all replaced with 0.0.1-security sentinel tarballs. Private registry mirrors (Verdaccio, Artifactory, Nexus) that cached the tarballs during the publish window WILL keep serving the original versions after the public yank - lockfile hits on these names must be treated as actionable regardless of what the public registry currently returns
What to do

Clean-up steps

  1. Grep 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. If you had streak-daycount, streak-calendar, or svelte-streaks in a lockfile: the near-simultaneous publish→take-down cadence across the three names indicates a single coordinated actor. Rotate npm, GitHub, and CI/CD tokens the install could have reached; audit postinstall logs for the ~8-hour exposure window between publish (14:56 UTC) and security-replacement (23:16 UTC) on 2026-07-21
  3. If you had @apexfdn/apex in a lockfile: this strongly indicates a misconfigured internal-registry resolver - the @apexfdn scope is unregistered on public npm and reads as an internal "Apex Foundation" scope. Audit the resolver order in .npmrc (private registry MUST be listed before the public registry for internal-scope names), register @apexfdn defensively on the public npm registry if your org uses that scope internally, and consider tightening .npmrc to @apexfdn:registry=https://<private-registry>/ so the public registry is never queried for this scope. Any of the 33 published versions 1.0.0 → 1.0.32 should be treated as compromised
  4. If you had nolby in a lockfile: any of the four versions 1.0.0 → 1.0.3 should be treated as compromised. The publish times cluster in a 4-hour window, so a lockfile pinned to any of them received the same payload family
  5. If you had veskra in a lockfile: only 0.0.1-security remains resolvable - the original version(s) were pulled from the public registry before the sentinel replacement. Grep every lockfile for veskra at any non-0.0.1-security version and treat any hit as actionable
  6. Verify none of the 6 listed packages still resolves via your private mirror - internal Artifactory / Nexus / Verdaccio instances routinely cache tarballs and will keep serving the original versions after the public yank
  7. For projects using postinstall-scripting packages, consider running npm install --ignore-scripts in CI as a defense-in-depth measure and re-invoking scripts only for vetted first-party packages
References

Sources

npm-2026-07-21-ghsa-malware-sweepBack to incidentsSubmit a correction
Am I affected?

Check your lockfile against this and every other incident.

Paste a lockfile and it is matched on your own device against every compromised version we track. Nothing is uploaded and there is no account.