Feed
HighPublished 29 Jun 2026Updated 1 Jul 202610 packages · 10 versions

Internal-scope dependency-confusion cluster (Deel, Webda, Citi, BSCom, TiVo, CSEO-HR, +) taken down 2026-06-29

Summary

Between 2026-04-27 and 2026-05-31, ten npm packages impersonating internal corporate scopes — Deel, Webda, Citi ICG, BSCom, TiVo, CSEO-HR, Concerns, Via City Tools, WM — were published at 99.9.1 to win dependency-confusion resolution against the matching private mirrors. npm support unpublished the whole batch on 2026-06-29 between 16:46 and 16:52 UTC and replaced them with 0.0.1-security holders; GHSA records dropped the same day.

dependency-confusioncredential-theft
Detected by
GitHub Security
Also known as
99.9.1 internal-scope squat cluster
Ecosystems
npm
Packages tracked
10

What happened

On 2026-06-29 between 16:46 and 16:52 UTC, npm support unpublished ten malicious packages within a six-minute window and replaced each with the standard 0.0.1-security holding-package placeholder. GitHub Advisories (CWE-506) dropped the same day.

All ten follow an identical dependency-confusion pattern. Each package was published under a scope that visibly matches an internal corporate namespace, and each shipped exactly one version: 99.9.1 — a deliberately high SemVer that wins resolution against any internal release in the realistic 0.x / 1.x / 2.x range. The earliest squat (@cseo-hr/trpweb-shared) was live from 2026-05-21 18:21 UTC; the latest (@webda-infra-ui/static-images) from 2026-05-31 10:52 UTC.

The GHSA records all use the standard malware-classification boilerplate ("any computer that has this package installed or running should be considered fully compromised") and do not include a payload write-up, so defenders should treat the install-time behaviour as unanalysed and assume worst case. The coordinated ~6-minute takedown window is the npm trust-and-safety team's standard response when they're working through a reported batch; it does not by itself imply single-operator attribution, only that the batch was reported / triaged together. The Deel-, Webda-, Citi-, BSCom-, TiVo-, and CSEO-HR-targeted scopes are however a recognisable named-target pattern that maps to the same dependency-confusion playbook used in the 2026-05-28 oob.moika.tech burst (@cloudplatform-single-spa, @t-in-one, @sber-ecom-core) and earlier campaigns against @nrwl, @cap-js, and others.

Per-package detail

  • @cseo-hr/trpweb-shared — published 2026-05-21 18:21 UTC at 99.9.1. Squat under a @cseo-hr HR-app scope. Replaced 2026-06-29 16:49 UTC.
  • @citi-icg-171632/citicms-repo-component — published 2026-05-22 13:10 UTC at 99.9.1. Squat against an internal Citi Institutional Clients Group "171632" CMS scope. Replaced 2026-06-29 16:48 UTC.
  • @bscom/styling — published 2026-05-22 13:17 UTC at 99.9.1. Squat against BSCom (Brasil Segurança / BS.com) internal styling library scope. Replaced 2026-06-29 16:48 UTC.
  • @concerns/i18n — published 2026-05-22 12:58 UTC at 99.9.1. Squat against an internal @concerns i18n scope. Replaced 2026-06-29 16:49 UTC.
  • wm-mapper — published 2026-05-26 17:25 UTC at 99.9.1. Unscoped squat targeting a WM-branded internal mapper package. Replaced 2026-06-29 16:46 UTC.
  • via-city-tools-m-particle — published 2026-05-26 17:47 UTC at 99.9.1. Unscoped squat targeting a Via City Tools mParticle analytics integration. Replaced 2026-06-29 16:46 UTC.
  • tivo-codelib-a — published 2026-05-28 13:24 UTC at 99.9.1. Unscoped squat targeting a TiVo internal code library. Replaced 2026-06-29 16:46 UTC.
  • @webd-infra/query-designer-domain — published 2026-05-31 10:43 UTC at 99.9.1. Paired squat under a slightly different namespacing (@webd-infra vs @webda-infra-ui) against the same parent organisation. Replaced 2026-06-29 16:52 UTC.
  • @webda-infra-ui/static-images — published 2026-05-31 10:52 UTC at 99.9.1. Squat under the @webda-infra-ui scope (asset / static-image companion to a UI framework). Replaced 2026-06-29 16:51 UTC.
  • @deel-ui/animation — published 2026-04-27 09:39 UTC at 99.9.1. Squat against Deel's internal UI library scope. Replaced 2026-06-29 16:50 UTC. (See also the 2026-05-28 @t-in-one burst under the same Deel target ecosystem.)

Affected packages (10)

  • npm@bscom/styling
    99.9.1
  • npm@citi-icg-171632/citicms-repo-component
    99.9.1
  • npm@concerns/i18n
    99.9.1
  • npm@cseo-hr/trpweb-shared
    99.9.1
  • npm@deel-ui/animation
    99.9.1
  • npm@webd-infra/query-designer-domain
    99.9.1
  • npm@webda-infra-ui/static-images
    99.9.1
  • npmtivo-codelib-a
    99.9.1
  • npmvia-city-tools-m-particle
    99.9.1
  • npmwm-mapper
    99.9.1

Impact

  • Dependency-confusion: each package was published at 99.9.1, far above any plausible internal version, so any build that resolves an unscoped name like @deel-ui/animation against the public npm registry would pull the malicious tarball instead of the internal mirror copy
  • Targets named-organisation internal scopes: Deel (@deel-ui), Webda (@webda-infra-ui, @webd-infra), Citi ICG (@citi-icg-171632), BSCom (@bscom), CSEO-HR (@cseo-hr), Concerns (@concerns), TiVo (tivo-codelib-a), Via City Tools (via-city-tools-m-particle), and WM (wm-mapper) — strong signal the operator enumerated leaked package-lock.json files or build manifests before registering the squats
  • GHSA-classified as CWE-506 (embedded malicious code); GitHub treats any computer that installed any of these as fully compromised
  • No second-stage payload analysis is published in the GHSA records — defenders should treat the affected runtime as having executed arbitrary attacker code on the npm install lifecycle
  • Long exposure window: the earliest squat (@cseo-hr/trpweb-shared) was live from 2026-05-21 21:21 UTC and the latest (@webda-infra-ui/static-images) from 2026-05-31 10:52 UTC — between 4 and 5+ weeks before the coordinated 2026-06-29 takedown

What to do

  1. 1Audit package.json and lockfiles for any dependency under @deel-ui, @webda-infra-ui, @webd-infra, @citi-icg-171632, @bscom, @cseo-hr, @concerns, or any unscoped tivo-codelib-*, via-city-tools-*, or wm-mapper — see the packages map below for the exact names
  2. 2If your build ever resolved 99.9.1 of any of these against the public registry: treat the build runner and any artefact it produced as compromised. Rotate every credential reachable from that runner from a separate clean device
  3. 3Register 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
  4. 4Pin your registry: use .npmrc to route scoped names to your internal mirror only (e.g. @deel-ui:registry=https://internal/), so the public-registry path is never queried
  5. 5Hunt build logs and CI cache history (artifact storage, GHA cache, npm cache) for any prior install of 99.9.1 under any of the ten affected package names — npm has now unpublished the tarballs but pre-takedown installs would have executed the payload

References

npm-2026-06-29-internal-scope-dep-confusion-cluster