GitHub Advisory malware sweep — 3-package `streak-*` habit-tracker cluster, `@apexfdn/apex` 33-version dependency-confusion burst, `nolby` 4-version rapid-burst, and `veskra` singleton swept 2026-07-21
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.
- 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
- Ecosystems
- npm
- Packages tracked
- 6
What happened
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)
| Package | Versions | Publish window (UTC) | npm security-replace (UTC) | |---|---|---|---| | streak-daycount | 1.0.0 | 2026-07-21 14:56:04 | 2026-07-21 23:16:40 | | svelte-streaks | 1.0.0 → 1.0.2 | 2026-07-21 14:56:14 → 15:52:49 | 2026-07-21 23:17:02 | | streak-calendar | 1.0.0 → 1.0.1 | 2026-07-21 15:17:37 → 15:52:37 | 2026-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)
| Package | Versions | Publish window (UTC) | npm security-replace (UTC) | |---|---|---|---| | @apexfdn/apex | 1.0.0 → 1.0.32 (33 versions) | 2026-07-05 → 2026-07-21 | 2026-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)
| Package | Versions | Publish window (UTC) | npm security-replace (UTC) | |---|---|---|---| | nolby | 1.0.0 → 1.0.3 (4 versions) | 2026-07-21 05:42:46 → 09:27:35 | 2026-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)
| Package | Versions | Publish window (UTC) | npm security-replace (UTC) | |---|---|---|---| | veskra | (original versions no longer resolvable) | pre-2026-07-21 | 2026-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.
Affected packages (6)
- npm
@apexfdn/apex1.0.01.0.11.0.21.0.31.0.41.0.51.0.61.0.71.0.81.0.91.0.101.0.111.0.121.0.131.0.141.0.151.0.161.0.171.0.181.0.191.0.201.0.211.0.221.0.231.0.241.0.251.0.261.0.271.0.281.0.291.0.301.0.311.0.32 - npm
nolby1.0.01.0.11.0.21.0.3 - npm
streak-calendar1.0.01.0.1 - npm
streak-daycount1.0.0 - npm
svelte-streaks1.0.01.0.11.0.2 - npm
veskra
Impact
- 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), andsvelte-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 with0.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/apex33-version dependency-confusion burst (1 package): 33 versions1.0.0→1.0.32published across 17 days from 2026-07-05 → 2026-07-21, then npm-security-replaced 2026-07-21 UTC. The@apexfdnscope 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 scopeapexfdnreads as "Apex Foundation" — a likely internal-registry scope name at a specific organisation. Any lockfile pin on@apexfdn/apexindicates the resolver picked the public malicious tarball over the intended private onenolby4-version rapid-burst (1 package): 4 versions1.0.0→1.0.3published 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 behaviorveskrasingleton (1 package): the pre-existingveskraname 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 pinnedveskraat any version prior to0.0.1-securityis affected- None of the 6 packages have surviving version tarballs on the public npm registry — all replaced with
0.0.1-securitysentinel 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
- 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 - 2If you had
streak-daycount,streak-calendar, orsvelte-streaksin 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; auditpostinstalllogs for the ~8-hour exposure window between publish (14:56 UTC) and security-replacement (23:16 UTC) on 2026-07-21 - 3If you had
@apexfdn/apexin a lockfile: this strongly indicates a misconfigured internal-registry resolver — the@apexfdnscope 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@apexfdndefensively on the public npm registry if your org uses that scope internally, and consider tightening.npmrcto@apexfdn:registry=https://<private-registry>/so the public registry is never queried for this scope. Any of the 33 published versions1.0.0→1.0.32should be treated as compromised - 4If you had
nolbyin a lockfile: any of the four versions1.0.0→1.0.3should 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 - 5If you had
veskrain a lockfile: only0.0.1-securityremains resolvable — the original version(s) were pulled from the public registry before the sentinel replacement. Grep every lockfile forveskraat any non-0.0.1-securityversion and treat any hit as actionable - 6Verify 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
- 7For projects using
postinstall-scripting packages, consider runningnpm install --ignore-scriptsin CI as a defense-in-depth measure and re-invoking scripts only for vetted first-party packages
References
- GitHubGitHub Advisory Database — recent npm malware advisoriesgithub.com
- GitHubGHSA-2v57-6hmf-hpfj — streak-daycount malware advisorygithub.com
- GitHubGHSA-8vq2-5c69-fm3w — svelte-streaks malware advisorygithub.com
- GitHubGHSA-2p69-mmpj-h84r — streak-calendar malware advisorygithub.com
- GitHubGHSA-w63r-vpcf-2wwf — @apexfdn/apex malware advisorygithub.com
- GitHubGHSA-pr2p-6xpw-q8vw — veskra malware advisorygithub.com
- GitHubGHSA-x724-q7wp-wx6q — nolby malware advisorygithub.com