Internal-scope dependency-confusion cluster (Deel, Webda, Citi, BSCom, TiVo, CSEO-HR, +) taken down 2026-06-29
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.
- 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 at99.9.1. Squat under a@cseo-hrHR-app scope. Replaced 2026-06-29 16:49 UTC.@citi-icg-171632/citicms-repo-component— published 2026-05-22 13:10 UTC at99.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 at99.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 at99.9.1. Squat against an internal@concernsi18n scope. Replaced 2026-06-29 16:49 UTC.wm-mapper— published 2026-05-26 17:25 UTC at99.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 at99.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 at99.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 at99.9.1. Paired squat under a slightly different namespacing (@webd-infravs@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 at99.9.1. Squat under the@webda-infra-uiscope (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 at99.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-oneburst under the same Deel target ecosystem.)
Affected packages (10)
- npm
@bscom/styling99.9.1 - npm
@citi-icg-171632/citicms-repo-component99.9.1 - npm
@concerns/i18n99.9.1 - npm
@cseo-hr/trpweb-shared99.9.1 - npm
@deel-ui/animation99.9.1 - npm
@webd-infra/query-designer-domain99.9.1 - npm
@webda-infra-ui/static-images99.9.1 - npm
tivo-codelib-a99.9.1 - npm
via-city-tools-m-particle99.9.1 - npm
wm-mapper99.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/animationagainst 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 installlifecycle - 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
- 1Audit
package.jsonand lockfiles for any dependency under@deel-ui,@webda-infra-ui,@webd-infra,@citi-icg-171632,@bscom,@cseo-hr,@concerns, or any unscopedtivo-codelib-*,via-city-tools-*, orwm-mapper— see the packages map below for the exact names - 2If your build ever resolved
99.9.1of 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 - 3Register every internal
@scopeyou use on the public npm registry (even as a stub) so a future dependency-confusion squat under the same scope cannot resolve - 4Pin your registry: use
.npmrcto route scoped names to your internal mirror only (e.g.@deel-ui:registry=https://internal/), so the public-registry path is never queried - 5Hunt build logs and CI cache history (artifact storage, GHA cache, npm cache) for any prior install of
99.9.1under any of the ten affected package names — npm has now unpublished the tarballs but pre-takedown installs would have executed the payload
References
- GitHubGHSA-9rwq-pr4x-fhqg — @deel-ui/animation malware advisorygithub.com
- GitHubGHSA-pp6c-f2ph-gxmm — @webda-infra-ui/static-images malware advisorygithub.com
- GitHubGHSA-7c4p-cm4f-hwp2 — @webd-infra/query-designer-domain malware advisorygithub.com
- GitHubGHSA-prgj-vfx3-5cqv — @citi-icg-171632/citicms-repo-component malware advisorygithub.com
- GitHubGHSA-29c6-c7cm-r8ch — @bscom/styling malware advisorygithub.com
- GitHubGHSA-rp2m-w359-5cqp — @concerns/i18n malware advisorygithub.com
- GitHubGHSA-5x3r-97g5-r9j5 — @cseo-hr/trpweb-shared malware advisorygithub.com
- GitHubGHSA-6wg4-xxqc-hw9h — via-city-tools-m-particle malware advisorygithub.com
- GitHubGHSA-vqvw-vx7g-vp4p — wm-mapper malware advisorygithub.com
- GitHubGHSA-4f5g-pqjq-3mvw — tivo-codelib-a malware advisorygithub.com
- npm@deel-ui/animation on npm (now 0.0.1-security holding)npmjs.com
- npm@citi-icg-171632/citicms-repo-component on npm (now 0.0.1-security holding)npmjs.com