# GitHub Advisory malware sweep - 4-package `app-data-*` / `app-node-*` v2.1.6 typosquat cluster (`app-data-layer`, `app-node-layer`, `app-data-ist`, `app-data-lts`) coordinated security-replace on 2026-07-24

> On 2026-07-24 17:19:21 → 17:19:45 UTC (a 24-second window) GitHub retired **4 npm CWE-506 malware advisories** for a tight `app-*`-prefixed typosquat/dependency-confusion cluster: `app-data-layer`, `app-node-layer`, `app-data-ist`, `app-data-lts` - all published as `2.1.6`, all detected in a single coordinated pipeline sweep.

- Published: 2026-07-24
- Last updated: 2026-07-25
- Severity: high
- Kind: 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.
- Ecosystems: npm
- Scope: 4 packages, 4 compromised versions
- Tags: typosquat, dependency-confusion
- Also known as: 2026-07-24 GHSA npm app-* cluster sweep, app-*-layer v2.1.6 cluster
- Detected by: GitHub Advisory Database, npm Security
- Incident ID: npm-2026-07-24-app-cluster-ghsa-sweep

## Affected packages (4)

Only the exact versions listed were named by the source advisories. Other versions are not implicated.

| Package | Ecosystem | Compromised versions |
|---|---|---|
| [app-data-ist](https://dependencywatch.io/package/npm/app-data-ist) | npm | 2.1.6 |
| [app-data-layer](https://dependencywatch.io/package/npm/app-data-layer) | npm | 2.1.6 |
| [app-data-lts](https://dependencywatch.io/package/npm/app-data-lts) | npm | 2.1.6 |
| [app-node-layer](https://dependencywatch.io/package/npm/app-node-layer) | npm | 2.1.6 |

## What happened

On 2026-07-24 GitHub's Advisory Database security-replaced **4 npm packages** in a coordinated 24-second window as CWE-506 (Embedded Malicious Code) malware. The tight coordination - and the uniform `2.1.6` version across all 4 packages - is the signature of a single-operator typosquat or dependency-confusion campaign targeting Adobe App Builder / AIO tooling or generic `app-*` internal-registry names.

## Cluster - `app-*` v2.1.6 typosquat/dep-confusion (4 packages)

| Package | Version | Publish (UTC) | npm security-replace (UTC) | Time on registry |
|---|---|---|---|---|
| `app-data-lts` | `2.1.6` | 2026-07-20 17:56:09 | 2026-07-24 17:19:40 | ~3d 23h |
| `app-data-layer` | `2.1.6` | 2026-07-20 21:32:20 | 2026-07-24 17:19:35 | ~3d 20h |
| `app-data-ist` | `2.1.6` | 2026-07-21 04:38:11 | 2026-07-24 17:19:21 | ~3d 13h |
| `app-node-layer` | `2.1.6` | 2026-07-24 16:40:37 | 2026-07-24 17:19:45 | ~39 minutes |

All four security-replacements landed within a **24-second window** at 2026-07-24 17:19:21 → 17:19:45 UTC - the tightest coordinated take-down cadence recorded on any GHSA npm batch in July 2026. The GHSA IDs are:

- `GHSA-346c-3w9c-8pmh` - `app-data-layer`
- `GHSA-4xc7-2jx9-rp5j` - `app-node-layer`
- `GHSA-wcx6-x67q-wff5` - `app-data-ist`
- `GHSA-c6xr-m3x3-23fm` - `app-data-lts`

All 4 advisories 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.

## Attribution signals

### Naming pattern

The `app-*` prefix with `-data-*` / `-node-*` suffixes matches multiple internal-registry conventions:

- **Adobe App Builder / AIO tooling**: Adobe uses `@adobe/aio-*` scopes canonically, but `app-*` public names have been targeted before - the 2026-07-23 GHSA sweep captured `aio-commerce-lib-app@110.0.0` as a dependency-confusion attempt against Adobe internal registries. This cluster may be the same operator returning with a typosquat-oriented variant (`2.1.6` rather than `110.x`)
- **Generic frontend/backend layer naming**: `-data-layer`, `-node-layer`, `-data-lts` (long-term support), `-data-ist` (installer/interstitial?) are all plausible internal names for a monorepo's data-access and Node runtime layers. Any organisation with a private monorepo using these names is vulnerable to dependency confusion

### Version choice

The uniform `2.1.6` version across all 4 packages is unusual - it is neither the very-low `1.0.0` typical of throwaway typosquats nor the very-high `110.x` / `22.x` typical of dependency-confusion attacks. `2.1.6` is an intentional-looking mid-range version, consistent with the operator wanting the packages to appear mature (installers tend to pin to `^2.x` rather than `^1.x`, and semver ranges resolve `2.1.6` as the highest compatible for `^2.1.0`).

### Coordinated take-down

A 24-second security-replace window across 4 packages is not accidental - GitHub's malware pipeline batched these based on shared indicators (payload signature, publisher account, upload IP, or dependency graph). This is consistent with the 2-minute batching observed on the 2026-07-23 `ethers-packge` / `@bcryptln/*` crypto cluster.

## Registry state

All 4 packages were npm-security-replaced (`0.0.1-security` sentinel tarball at `latest` dist-tag). Original `2.1.6` tarballs are no longer resolvable on the public registry, but private registry mirrors that cached the tarballs during the publish windows 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.

## 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
- **`app-*`-prefixed 4-package cluster** - all `2.1.6`: `app-data-layer@2.1.6` (published 2026-07-20 21:32:20 UTC, ~4 days on the registry), `app-data-lts@2.1.6` (published 2026-07-20 17:56:09 UTC, ~4 days), `app-data-ist@2.1.6` (published 2026-07-21 04:38:11 UTC, ~3.5 days), `app-node-layer@2.1.6` (published 2026-07-24 16:40:37 UTC - just 39 minutes before take-down). All four were security-replaced within a **24-second window** at 2026-07-24 17:19:21 → 17:19:45 UTC - the tightest coordinated take-down cadence recorded on any GHSA npm batch this month, strongly indicating GitHub's malware pipeline flagged them as a single related campaign
- The uniform `2.1.6` version choice across all 4 packages, combined with the `app-` prefix and matching `-data-*` / `-node-*` name suffixes, is consistent with either a **typosquat** (aping Adobe App Builder / AIO tooling - the previous 2026-07-23 sweep already flagged `aio-commerce-lib-app` at `110.0.0` as a dependency-confusion attempt against Adobe internal registries) or **dependency-confusion** against generic `app-*` internal registry names. Choosing `2.1.6` (an intentional-looking mid-range version) rather than the very-high dep-confusion pattern (`110.x`, `22.x`) suggests the operator was optimising for typosquat plausibility over registry-precedence
- `app-node-layer` has the shortest publish→take-down window in the cluster - just **39 minutes** on the registry (published 16:40:37 UTC, security-replaced 17:19:45 UTC). This mirrors the rapid detection-response window observed with `vitest-axios` and `fs-extra-core` in the 2026-07-23 sweep (40-67 minutes each) and confirms GitHub's malware pipeline is catching same-day-published typosquats reliably
- `app-data-layer`, `app-data-ist`, and `app-data-lts` had 3.5-4 days on the registry each before take-down, which is enough time for automated dependency-refresh workflows (Renovate, Dependabot, `npm audit fix`, weekly CI lockfile updates) to have pulled the tarballs into build caches. Any Node.js project running such workflows against a package.json referencing a bare `app-data-*` name should audit their `node_modules` snapshots for the compromised `2.1.6`
- None of the 4 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 ~4-day 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

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 any `app-data-*` or `app-node-*` package in a lockfile**: verify whether the intended dependency is an Adobe App Builder / AIO internal-registry name (Adobe uses `@adobe/aio-*` scopes and the `aio-` prefix - the `app-*` prefix used here is NOT the canonical Adobe naming, so any resolution against these public packages is a typosquat/dep-confusion event). Cross-check whether your project also had `aio-commerce-lib-app@110.0.0` from the 2026-07-23 sweep - the same operator may have used both naming variants
3. For any project targeting Adobe App Builder / AIO deployments: audit your CI/CD pipeline for these 4 package names, and configure your private registry mirror (Verdaccio, Artifactory, Nexus) with **scoped resolution** so that public packages cannot shadow internal names during a lockfile refresh
4. Verify none of the 4 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. Any cached `2.1.6` tarball must be purged from mirror caches
5. 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
6. If your build runners had access to Adobe I/O Runtime credentials, AWS/GCP metadata endpoints, or cloud storage keys during a lockfile refresh window that pulled any `app-*@2.1.6` tarball: rotate those credentials from a clean workstation and audit access logs for exfiltration attempts to attacker-controlled endpoints during the exposure window

## Check your own dependencies

- Check a package-lock.json against this incident: https://dependencywatch.io/check/package-lock-json

The scan runs entirely in the browser; lockfile contents are never uploaded.

## References

- [GitHub Advisory Database - recent npm malware advisories](https://github.com/advisories?query=type%3Amalware+ecosystem%3Anpm&sort=published-desc) - GitHub
- [GHSA-346c-3w9c-8pmh - app-data-layer malware advisory](https://github.com/advisories/GHSA-346c-3w9c-8pmh) - GitHub
- [GHSA-4xc7-2jx9-rp5j - app-node-layer malware advisory](https://github.com/advisories/GHSA-4xc7-2jx9-rp5j) - GitHub
- [GHSA-wcx6-x67q-wff5 - app-data-ist malware advisory](https://github.com/advisories/GHSA-wcx6-x67q-wff5) - GitHub
- [GHSA-c6xr-m3x3-23fm - app-data-lts malware advisory](https://github.com/advisories/GHSA-c6xr-m3x3-23fm) - GitHub

---

Canonical page: https://dependencywatch.io/incident/npm-2026-07-24-app-cluster-ghsa-sweep
Markdown version: https://dependencywatch.io/incident/npm-2026-07-24-app-cluster-ghsa-sweep.md
Site index for agents: https://dependencywatch.io/llms.txt
DependencyWatch.io is operated by Precursor Security (https://precursorsecurity.com).
