# Original Shai-Hulud npm worm

> First successful self-propagating worm in the npm ecosystem. Downstream of the August 2025 s1ngularity/Nx GitHub-token theft. The postinstall hook ran TruffleHog to harvest secrets, opened public GitHub repos named "Shai-Hulud" to publish them, force-converted private repos to public with a "-migration" suffix, and used stolen npm tokens to publish malicious versions of any package the maintainer could access. ~180 unique packages compromised across 300+ versions, including CrowdStrike's own scope (@crowdstrike/*).

- Published: 2025-09-15
- Severity: critical
- Kind: Compromise - A legitimate, already-used package, maintainer account, CI pipeline, or release tag was hijacked and a malicious version was published under a name people already depend on.
- Ecosystems: npm
- Scope: 197 packages, 509 compromised versions
- Tags: worm, infostealer, credential-theft, account-takeover, maintainer-takeover
- Also known as: Shai-Hulud, s1ngularity downstream
- Detected by: StepSecurity, Socket, Aikido, Wiz
- Incident ID: npm-2025-09-shai-hulud-original

## Affected packages (197)

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

| Package | Ecosystem | Compromised versions |
|---|---|---|
| [@ahmedhfarag/ngx-perfect-scrollbar](https://dependencywatch.io/package/npm/@ahmedhfarag/ngx-perfect-scrollbar) | npm | 20.0.20 |
| [@ahmedhfarag/ngx-virtual-scroller](https://dependencywatch.io/package/npm/@ahmedhfarag/ngx-virtual-scroller) | npm | 4.0.4 |
| [@art-ws/common](https://dependencywatch.io/package/npm/@art-ws/common) | npm | 2.0.28 |
| [@art-ws/config-eslint](https://dependencywatch.io/package/npm/@art-ws/config-eslint) | npm | 2.0.4, 2.0.5 |
| [@art-ws/config-ts](https://dependencywatch.io/package/npm/@art-ws/config-ts) | npm | 2.0.7, 2.0.8 |
| [@art-ws/db-context](https://dependencywatch.io/package/npm/@art-ws/db-context) | npm | 2.0.24 |
| [@art-ws/di](https://dependencywatch.io/package/npm/@art-ws/di) | npm | 2.0.28, 2.0.32 |
| [@art-ws/di-node](https://dependencywatch.io/package/npm/@art-ws/di-node) | npm | 2.0.13 |
| [@art-ws/eslint](https://dependencywatch.io/package/npm/@art-ws/eslint) | npm | 1.0.5, 1.0.6 |
| [@art-ws/fastify-http-server](https://dependencywatch.io/package/npm/@art-ws/fastify-http-server) | npm | 2.0.24, 2.0.27 |
| [@art-ws/http-server](https://dependencywatch.io/package/npm/@art-ws/http-server) | npm | 2.0.21, 2.0.25 |
| [@art-ws/openapi](https://dependencywatch.io/package/npm/@art-ws/openapi) | npm | 0.1.9, 0.1.12 |
| [@art-ws/package-base](https://dependencywatch.io/package/npm/@art-ws/package-base) | npm | 1.0.5, 1.0.6 |
| [@art-ws/prettier](https://dependencywatch.io/package/npm/@art-ws/prettier) | npm | 1.0.5, 1.0.6 |
| [@art-ws/slf](https://dependencywatch.io/package/npm/@art-ws/slf) | npm | 2.0.15, 2.0.22 |
| [@art-ws/ssl-info](https://dependencywatch.io/package/npm/@art-ws/ssl-info) | npm | 1.0.9, 1.0.10 |
| [@art-ws/web-app](https://dependencywatch.io/package/npm/@art-ws/web-app) | npm | 1.0.3, 1.0.4 |
| [@basic-ui-components-stc/basic-ui-components](https://dependencywatch.io/package/npm/@basic-ui-components-stc/basic-ui-components) | npm | 1.0.5 |
| [@crowdstrike/commitlint](https://dependencywatch.io/package/npm/@crowdstrike/commitlint) | npm | 8.1.1, 8.1.2 |
| [@crowdstrike/falcon-shoelace](https://dependencywatch.io/package/npm/@crowdstrike/falcon-shoelace) | npm | 0.4.1, 0.4.2 |
| [@crowdstrike/foundry-js](https://dependencywatch.io/package/npm/@crowdstrike/foundry-js) | npm | 0.19.1, 0.19.2 |
| [@crowdstrike/glide-core](https://dependencywatch.io/package/npm/@crowdstrike/glide-core) | npm | 0.34.2, 0.34.3 |
| [@crowdstrike/logscale-dashboard](https://dependencywatch.io/package/npm/@crowdstrike/logscale-dashboard) | npm | 1.205.1, 1.205.2 |
| [@crowdstrike/logscale-file-editor](https://dependencywatch.io/package/npm/@crowdstrike/logscale-file-editor) | npm | 1.205.1, 1.205.2 |
| [@crowdstrike/logscale-parser-edit](https://dependencywatch.io/package/npm/@crowdstrike/logscale-parser-edit) | npm | 1.205.1, 1.205.2 |
| [@crowdstrike/logscale-search](https://dependencywatch.io/package/npm/@crowdstrike/logscale-search) | npm | 1.205.1, 1.205.2 |
| [@crowdstrike/tailwind-toucan-base](https://dependencywatch.io/package/npm/@crowdstrike/tailwind-toucan-base) | npm | 5.0.1, 5.0.2 |
| [@ctrl/deluge](https://dependencywatch.io/package/npm/@ctrl/deluge) | npm | 7.2.1, 7.2.2 |
| [@ctrl/golang-template](https://dependencywatch.io/package/npm/@ctrl/golang-template) | npm | 1.4.2, 1.4.3 |
| [@ctrl/magnet-link](https://dependencywatch.io/package/npm/@ctrl/magnet-link) | npm | 4.0.3, 4.0.4 |
| [@ctrl/ngx-codemirror](https://dependencywatch.io/package/npm/@ctrl/ngx-codemirror) | npm | 7.0.1, 7.0.2 |
| [@ctrl/ngx-csv](https://dependencywatch.io/package/npm/@ctrl/ngx-csv) | npm | 6.0.1, 6.0.2 |
| [@ctrl/ngx-emoji-mart](https://dependencywatch.io/package/npm/@ctrl/ngx-emoji-mart) | npm | 9.2.1, 9.2.2 |
| [@ctrl/ngx-rightclick](https://dependencywatch.io/package/npm/@ctrl/ngx-rightclick) | npm | 4.0.1, 4.0.2 |
| [@ctrl/qbittorrent](https://dependencywatch.io/package/npm/@ctrl/qbittorrent) | npm | 9.7.1, 9.7.2 |
| [@ctrl/react-adsense](https://dependencywatch.io/package/npm/@ctrl/react-adsense) | npm | 2.0.1, 2.0.2 |
| [@ctrl/shared-torrent](https://dependencywatch.io/package/npm/@ctrl/shared-torrent) | npm | 6.3.1, 6.3.2 |
| [@ctrl/tinycolor](https://dependencywatch.io/package/npm/@ctrl/tinycolor) | npm | 4.1.1, 4.1.2 |
| [@ctrl/torrent-file](https://dependencywatch.io/package/npm/@ctrl/torrent-file) | npm | 4.1.1, 4.1.2 |
| [@ctrl/transmission](https://dependencywatch.io/package/npm/@ctrl/transmission) | npm | 7.3.1 |
| [@ctrl/ts-base32](https://dependencywatch.io/package/npm/@ctrl/ts-base32) | npm | 4.0.1, 4.0.2 |
| [@hestjs/core](https://dependencywatch.io/package/npm/@hestjs/core) | npm | 0.2.1 |
| [@hestjs/cqrs](https://dependencywatch.io/package/npm/@hestjs/cqrs) | npm | 0.1.6 |
| [@hestjs/demo](https://dependencywatch.io/package/npm/@hestjs/demo) | npm | 0.1.2 |
| [@hestjs/eslint-config](https://dependencywatch.io/package/npm/@hestjs/eslint-config) | npm | 0.1.2 |
| [@hestjs/logger](https://dependencywatch.io/package/npm/@hestjs/logger) | npm | 0.1.6 |
| [@hestjs/scalar](https://dependencywatch.io/package/npm/@hestjs/scalar) | npm | 0.1.7 |
| [@hestjs/validation](https://dependencywatch.io/package/npm/@hestjs/validation) | npm | 0.1.6 |
| [@nativescript-community/arraybuffers](https://dependencywatch.io/package/npm/@nativescript-community/arraybuffers) | npm | 1.1.6, 1.1.7, 1.1.8 |
| [@nativescript-community/gesturehandler](https://dependencywatch.io/package/npm/@nativescript-community/gesturehandler) | npm | 2.0.35 |
| [@nativescript-community/perms](https://dependencywatch.io/package/npm/@nativescript-community/perms) | npm | 3.0.5, 3.0.6, 3.0.7, 3.0.8, 3.0.9 |
| [@nativescript-community/sentry](https://dependencywatch.io/package/npm/@nativescript-community/sentry) | npm | 4.6.43 |
| [@nativescript-community/sqlite](https://dependencywatch.io/package/npm/@nativescript-community/sqlite) | npm | 3.5.2, 3.5.3, 3.5.4, 3.5.5 |
| [@nativescript-community/text](https://dependencywatch.io/package/npm/@nativescript-community/text) | npm | 1.6.9, 1.6.10, 1.6.11, 1.6.12, 1.6.13 |
| [@nativescript-community/typeorm](https://dependencywatch.io/package/npm/@nativescript-community/typeorm) | npm | 0.2.30, 0.2.31, 0.2.32, 0.2.33 |
| [@nativescript-community/ui-collectionview](https://dependencywatch.io/package/npm/@nativescript-community/ui-collectionview) | npm | 6.0.6 |
| [@nativescript-community/ui-document-picker](https://dependencywatch.io/package/npm/@nativescript-community/ui-document-picker) | npm | 1.1.27, 1.1.28, 13.0.32 |
| [@nativescript-community/ui-drawer](https://dependencywatch.io/package/npm/@nativescript-community/ui-drawer) | npm | 0.1.30 |
| [@nativescript-community/ui-image](https://dependencywatch.io/package/npm/@nativescript-community/ui-image) | npm | 4.5.6 |
| [@nativescript-community/ui-label](https://dependencywatch.io/package/npm/@nativescript-community/ui-label) | npm | 1.3.35, 1.3.36, 1.3.37 |
| [@nativescript-community/ui-material-bottom-navigation](https://dependencywatch.io/package/npm/@nativescript-community/ui-material-bottom-navigation) | npm | 7.2.72, 7.2.73, 7.2.74, 7.2.75 |
| [@nativescript-community/ui-material-bottomsheet](https://dependencywatch.io/package/npm/@nativescript-community/ui-material-bottomsheet) | npm | 7.2.72 |
| [@nativescript-community/ui-material-core](https://dependencywatch.io/package/npm/@nativescript-community/ui-material-core) | npm | 7.2.72, 7.2.73, 7.2.74, 7.2.75, 7.2.76 |
| [@nativescript-community/ui-material-core-tabs](https://dependencywatch.io/package/npm/@nativescript-community/ui-material-core-tabs) | npm | 7.2.72, 7.2.73, 7.2.74, 7.2.75, 7.2.76 |
| [@nativescript-community/ui-material-ripple](https://dependencywatch.io/package/npm/@nativescript-community/ui-material-ripple) | npm | 7.2.72, 7.2.73, 7.2.74, 7.2.75 |
| [@nativescript-community/ui-material-tabs](https://dependencywatch.io/package/npm/@nativescript-community/ui-material-tabs) | npm | 7.2.72, 7.2.73, 7.2.74, 7.2.75 |
| [@nativescript-community/ui-pager](https://dependencywatch.io/package/npm/@nativescript-community/ui-pager) | npm | 14.1.36, 14.1.37, 14.1.38 |
| [@nativescript-community/ui-pulltorefresh](https://dependencywatch.io/package/npm/@nativescript-community/ui-pulltorefresh) | npm | 2.5.4, 2.5.5, 2.5.6, 2.5.7 |
| [@nexe/config-manager](https://dependencywatch.io/package/npm/@nexe/config-manager) | npm | 0.1.1 |
| [@nexe/eslint-config](https://dependencywatch.io/package/npm/@nexe/eslint-config) | npm | 0.1.1 |
| [@nexe/logger](https://dependencywatch.io/package/npm/@nexe/logger) | npm | 0.1.3 |
| [@nstudio/angular](https://dependencywatch.io/package/npm/@nstudio/angular) | npm | 20.0.4, 20.0.5, 20.0.6 |
| [@nstudio/focus](https://dependencywatch.io/package/npm/@nstudio/focus) | npm | 20.0.4, 20.0.5, 20.0.6 |
| [@nstudio/nativescript-checkbox](https://dependencywatch.io/package/npm/@nstudio/nativescript-checkbox) | npm | 2.0.6, 2.0.7, 2.0.8, 2.0.9 |
| [@nstudio/nativescript-loading-indicator](https://dependencywatch.io/package/npm/@nstudio/nativescript-loading-indicator) | npm | 5.0.1, 5.0.2, 5.0.3, 5.0.4 |
| [@nstudio/ui-collectionview](https://dependencywatch.io/package/npm/@nstudio/ui-collectionview) | npm | 5.1.11, 5.1.12, 5.1.13, 5.1.14 |
| [@nstudio/web](https://dependencywatch.io/package/npm/@nstudio/web) | npm | 20.0.4 |
| [@nstudio/web-angular](https://dependencywatch.io/package/npm/@nstudio/web-angular) | npm | 20.0.4 |
| [@nstudio/xplat](https://dependencywatch.io/package/npm/@nstudio/xplat) | npm | 20.0.5, 20.0.6, 20.0.7 |
| [@nstudio/xplat-utils](https://dependencywatch.io/package/npm/@nstudio/xplat-utils) | npm | 20.0.5, 20.0.6, 20.0.7 |
| [@operato/board](https://dependencywatch.io/package/npm/@operato/board) | npm | 9.0.36, 9.0.37, 9.0.38, 9.0.39, 9.0.40, 9.0.41, 9.0.42, 9.0.43, 9.0.44, 9.0.45, 9.0.46 |
| [@operato/data-grist](https://dependencywatch.io/package/npm/@operato/data-grist) | npm | 9.0.29, 9.0.35, 9.0.36, 9.0.37 |
| [@operato/graphql](https://dependencywatch.io/package/npm/@operato/graphql) | npm | 9.0.22, 9.0.35, 9.0.36, 9.0.37, 9.0.38, 9.0.39, 9.0.40, 9.0.41, 9.0.42, 9.0.43, 9.0.44, 9.0.45, 9.0.46 |
| [@operato/headroom](https://dependencywatch.io/package/npm/@operato/headroom) | npm | 9.0.2, 9.0.35, 9.0.36, 9.0.37 |
| [@operato/help](https://dependencywatch.io/package/npm/@operato/help) | npm | 9.0.35, 9.0.36, 9.0.37, 9.0.38, 9.0.39, 9.0.40, 9.0.41, 9.0.42, 9.0.43, 9.0.44, 9.0.45, 9.0.46 |
| [@operato/i18n](https://dependencywatch.io/package/npm/@operato/i18n) | npm | 9.0.35, 9.0.36, 9.0.37 |
| [@operato/input](https://dependencywatch.io/package/npm/@operato/input) | npm | 9.0.27, 9.0.35, 9.0.36, 9.0.37, 9.0.38, 9.0.39, 9.0.40, 9.0.41, 9.0.42, 9.0.43, 9.0.44, 9.0.45, 9.0.46, 9.0.47, 9.0.48 |
| [@operato/layout](https://dependencywatch.io/package/npm/@operato/layout) | npm | 9.0.35, 9.0.36, 9.0.37 |
| [@operato/popup](https://dependencywatch.io/package/npm/@operato/popup) | npm | 9.0.22, 9.0.35, 9.0.36, 9.0.37, 9.0.38, 9.0.39, 9.0.40, 9.0.41, 9.0.42, 9.0.43, 9.0.44, 9.0.45, 9.0.46, 9.0.49 |
| [@operato/pull-to-refresh](https://dependencywatch.io/package/npm/@operato/pull-to-refresh) | npm | 9.0.36, 9.0.37, 9.0.38, 9.0.39, 9.0.40, 9.0.41, 9.0.42 |
| [@operato/shell](https://dependencywatch.io/package/npm/@operato/shell) | npm | 9.0.22, 9.0.35, 9.0.36, 9.0.37, 9.0.38, 9.0.39 |
| [@operato/styles](https://dependencywatch.io/package/npm/@operato/styles) | npm | 9.0.2, 9.0.35, 9.0.36, 9.0.37 |
| [@operato/utils](https://dependencywatch.io/package/npm/@operato/utils) | npm | 9.0.22, 9.0.35, 9.0.36, 9.0.37, 9.0.38, 9.0.39, 9.0.40, 9.0.41, 9.0.42, 9.0.43, 9.0.44, 9.0.45, 9.0.46, 9.0.49 |
| [@teselagen/bio-parsers](https://dependencywatch.io/package/npm/@teselagen/bio-parsers) | npm | 0.4.29, 0.4.30 |
| [@teselagen/bounce-loader](https://dependencywatch.io/package/npm/@teselagen/bounce-loader) | npm | 0.3.16, 0.3.17 |
| [@teselagen/file-utils](https://dependencywatch.io/package/npm/@teselagen/file-utils) | npm | 0.3.21, 0.3.22 |
| [@teselagen/liquibase-tools](https://dependencywatch.io/package/npm/@teselagen/liquibase-tools) | npm | 0.4.1 |
| [@teselagen/ove](https://dependencywatch.io/package/npm/@teselagen/ove) | npm | 0.7.39, 0.7.40 |
| [@teselagen/range-utils](https://dependencywatch.io/package/npm/@teselagen/range-utils) | npm | 0.3.14, 0.3.15 |
| [@teselagen/react-list](https://dependencywatch.io/package/npm/@teselagen/react-list) | npm | 0.8.19, 0.8.20 |
| [@teselagen/react-table](https://dependencywatch.io/package/npm/@teselagen/react-table) | npm | 6.10.19, 6.10.20, 6.10.21, 6.10.22 |
| [@teselagen/sequence-utils](https://dependencywatch.io/package/npm/@teselagen/sequence-utils) | npm | 0.3.33, 0.3.34 |
| [@teselagen/ui](https://dependencywatch.io/package/npm/@teselagen/ui) | npm | 0.9.9, 0.9.10 |
| [@thangved/callback-window](https://dependencywatch.io/package/npm/@thangved/callback-window) | npm | 1.1.4 |
| [@things-factory/attachment-base](https://dependencywatch.io/package/npm/@things-factory/attachment-base) | npm | 9.0.42, 9.0.43, 9.0.44, 9.0.45, 9.0.46, 9.0.47, 9.0.48, 9.0.49, 9.0.50, 9.0.51, 9.0.52, 9.0.53, 9.0.54, 9.0.55 |
| [@things-factory/auth-base](https://dependencywatch.io/package/npm/@things-factory/auth-base) | npm | 9.0.42, 9.0.43, 9.0.44, 9.0.45 |
| [@things-factory/email-base](https://dependencywatch.io/package/npm/@things-factory/email-base) | npm | 9.0.42, 9.0.43, 9.0.44, 9.0.45, 9.0.46, 9.0.47, 9.0.48, 9.0.49, 9.0.50, 9.0.51, 9.0.52, 9.0.53, 9.0.54, 9.0.55, 9.0.56, 9.0.57, 9.0.58, 9.0.59 |
| [@things-factory/env](https://dependencywatch.io/package/npm/@things-factory/env) | npm | 9.0.42, 9.0.43, 9.0.44, 9.0.45 |
| [@things-factory/integration-base](https://dependencywatch.io/package/npm/@things-factory/integration-base) | npm | 9.0.42, 9.0.43, 9.0.44, 9.0.45 |
| [@things-factory/integration-marketplace](https://dependencywatch.io/package/npm/@things-factory/integration-marketplace) | npm | 9.0.42, 9.0.43, 9.0.44, 9.0.45 |
| [@things-factory/shell](https://dependencywatch.io/package/npm/@things-factory/shell) | npm | 9.0.42, 9.0.43, 9.0.44, 9.0.45 |
| [@tnf-dev/api](https://dependencywatch.io/package/npm/@tnf-dev/api) | npm | 1.0.8 |
| [@tnf-dev/core](https://dependencywatch.io/package/npm/@tnf-dev/core) | npm | 1.0.8 |
| [@tnf-dev/js](https://dependencywatch.io/package/npm/@tnf-dev/js) | npm | 1.0.8 |
| [@tnf-dev/mui](https://dependencywatch.io/package/npm/@tnf-dev/mui) | npm | 1.0.8 |
| [@tnf-dev/react](https://dependencywatch.io/package/npm/@tnf-dev/react) | npm | 1.0.8 |
| [@ui-ux-gang/devextreme-angular-rpk](https://dependencywatch.io/package/npm/@ui-ux-gang/devextreme-angular-rpk) | npm | 24.1.7 |
| [@yoobic/design-system](https://dependencywatch.io/package/npm/@yoobic/design-system) | npm | 6.5.17 |
| [@yoobic/jpeg-camera-es6](https://dependencywatch.io/package/npm/@yoobic/jpeg-camera-es6) | npm | 1.0.13 |
| [@yoobic/yobi](https://dependencywatch.io/package/npm/@yoobic/yobi) | npm | 8.7.53 |
| [airchief](https://dependencywatch.io/package/npm/airchief) | npm | 0.3.1 |
| [airpilot](https://dependencywatch.io/package/npm/airpilot) | npm | 0.8.8 |
| [angulartics2](https://dependencywatch.io/package/npm/angulartics2) | npm | 14.1.1, 14.1.2 |
| [browser-webdriver-downloader](https://dependencywatch.io/package/npm/browser-webdriver-downloader) | npm | 3.0.8 |
| [capacitor-notificationhandler](https://dependencywatch.io/package/npm/capacitor-notificationhandler) | npm | 0.0.2, 0.0.3 |
| [capacitor-plugin-healthapp](https://dependencywatch.io/package/npm/capacitor-plugin-healthapp) | npm | 0.0.2, 0.0.3 |
| [capacitor-plugin-ihealth](https://dependencywatch.io/package/npm/capacitor-plugin-ihealth) | npm | 1.1.8, 1.1.9 |
| [capacitor-plugin-vonage](https://dependencywatch.io/package/npm/capacitor-plugin-vonage) | npm | 1.0.2, 1.0.3 |
| [capacitorandroidpermissions](https://dependencywatch.io/package/npm/capacitorandroidpermissions) | npm | 0.0.4, 0.0.5 |
| [config-cordova](https://dependencywatch.io/package/npm/config-cordova) | npm | 0.8.5 |
| [cordova-plugin-voxeet2](https://dependencywatch.io/package/npm/cordova-plugin-voxeet2) | npm | 1.0.24 |
| [cordova-voxeet](https://dependencywatch.io/package/npm/cordova-voxeet) | npm | 1.0.32 |
| [create-hest-app](https://dependencywatch.io/package/npm/create-hest-app) | npm | 0.1.9 |
| [db-evo](https://dependencywatch.io/package/npm/db-evo) | npm | 1.1.4, 1.1.5 |
| [devextreme-angular-rpk](https://dependencywatch.io/package/npm/devextreme-angular-rpk) | npm | 21.2.8 |
| [devextreme-rpk](https://dependencywatch.io/package/npm/devextreme-rpk) | npm | 21.2.8 |
| [ember-browser-services](https://dependencywatch.io/package/npm/ember-browser-services) | npm | 5.0.2, 5.0.3 |
| [ember-headless-form](https://dependencywatch.io/package/npm/ember-headless-form) | npm | 1.1.2, 1.1.3 |
| [ember-headless-form-yup](https://dependencywatch.io/package/npm/ember-headless-form-yup) | npm | 1.0.1 |
| [ember-headless-table](https://dependencywatch.io/package/npm/ember-headless-table) | npm | 2.1.5, 2.1.6 |
| [ember-url-hash-polyfill](https://dependencywatch.io/package/npm/ember-url-hash-polyfill) | npm | 1.0.12, 1.0.13 |
| [ember-velcro](https://dependencywatch.io/package/npm/ember-velcro) | npm | 2.2.1, 2.2.2 |
| [encounter-playground](https://dependencywatch.io/package/npm/encounter-playground) | npm | 0.0.2, 0.0.3, 0.0.4, 0.0.5 |
| [eslint-config-crowdstrike](https://dependencywatch.io/package/npm/eslint-config-crowdstrike) | npm | 11.0.2, 11.0.3 |
| [eslint-config-crowdstrike-node](https://dependencywatch.io/package/npm/eslint-config-crowdstrike-node) | npm | 4.0.3, 4.0.4 |
| [eslint-config-teselagen](https://dependencywatch.io/package/npm/eslint-config-teselagen) | npm | 6.1.7, 6.1.8 |
| [globalize-rpk](https://dependencywatch.io/package/npm/globalize-rpk) | npm | 1.7.4 |
| [graphql-sequelize-teselagen](https://dependencywatch.io/package/npm/graphql-sequelize-teselagen) | npm | 5.3.8, 5.3.9 |
| [html-to-base64-image](https://dependencywatch.io/package/npm/html-to-base64-image) | npm | 1.0.2 |
| [json-rules-engine-simplified](https://dependencywatch.io/package/npm/json-rules-engine-simplified) | npm | 0.2.1, 0.2.3, 0.2.4 |
| [jumpgate](https://dependencywatch.io/package/npm/jumpgate) | npm | 0.0.2 |
| [koa2-swagger-ui](https://dependencywatch.io/package/npm/koa2-swagger-ui) | npm | 5.11.1, 5.11.2 |
| [mcfly-semantic-release](https://dependencywatch.io/package/npm/mcfly-semantic-release) | npm | 1.3.1 |
| [mcp-knowledge-base](https://dependencywatch.io/package/npm/mcp-knowledge-base) | npm | 0.0.2 |
| [mcp-knowledge-graph](https://dependencywatch.io/package/npm/mcp-knowledge-graph) | npm | 1.2.1 |
| [mobioffice-cli](https://dependencywatch.io/package/npm/mobioffice-cli) | npm | 1.0.3 |
| [monorepo-next](https://dependencywatch.io/package/npm/monorepo-next) | npm | 13.0.1, 13.0.2 |
| [mstate-angular](https://dependencywatch.io/package/npm/mstate-angular) | npm | 0.4.4 |
| [mstate-cli](https://dependencywatch.io/package/npm/mstate-cli) | npm | 0.4.7 |
| [mstate-dev-react](https://dependencywatch.io/package/npm/mstate-dev-react) | npm | 1.1.1 |
| [mstate-react](https://dependencywatch.io/package/npm/mstate-react) | npm | 1.6.5 |
| [ng2-file-upload](https://dependencywatch.io/package/npm/ng2-file-upload) | npm | 7.0.2, 7.0.3, 8.0.1, 8.0.2, 8.0.3, 9.0.1 |
| [ngx-bootstrap](https://dependencywatch.io/package/npm/ngx-bootstrap) | npm | 18.1.4, 19.0.3, 19.0.4, 20.0.3, 20.0.4, 20.0.5, 20.0.6 |
| [ngx-color](https://dependencywatch.io/package/npm/ngx-color) | npm | 10.0.1, 10.0.2 |
| [ngx-toastr](https://dependencywatch.io/package/npm/ngx-toastr) | npm | 19.0.1, 19.0.2 |
| [ngx-trend](https://dependencywatch.io/package/npm/ngx-trend) | npm | 8.0.1 |
| [ngx-ws](https://dependencywatch.io/package/npm/ngx-ws) | npm | 1.1.5, 1.1.6 |
| [oradm-to-gql](https://dependencywatch.io/package/npm/oradm-to-gql) | npm | 35.0.14, 35.0.15 |
| [oradm-to-sqlz](https://dependencywatch.io/package/npm/oradm-to-sqlz) | npm | 1.1.2, 1.1.4 |
| [ove-auto-annotate](https://dependencywatch.io/package/npm/ove-auto-annotate) | npm | 0.0.9, 0.0.10 |
| [pm2-gelf-json](https://dependencywatch.io/package/npm/pm2-gelf-json) | npm | 1.0.4, 1.0.5 |
| [printjs-rpk](https://dependencywatch.io/package/npm/printjs-rpk) | npm | 1.6.1 |
| [react-complaint-image](https://dependencywatch.io/package/npm/react-complaint-image) | npm | 0.0.32, 0.0.34, 0.0.35 |
| [react-jsonschema-form-conditionals](https://dependencywatch.io/package/npm/react-jsonschema-form-conditionals) | npm | 0.3.18, 0.3.20, 0.3.21 |
| [react-jsonschema-form-extras](https://dependencywatch.io/package/npm/react-jsonschema-form-extras) | npm | 1.0.3, 1.0.4 |
| [react-jsonschema-rxnt-extras](https://dependencywatch.io/package/npm/react-jsonschema-rxnt-extras) | npm | 0.4.8, 0.4.9 |
| [remark-preset-lint-crowdstrike](https://dependencywatch.io/package/npm/remark-preset-lint-crowdstrike) | npm | 4.0.1, 4.0.2 |
| [rxnt-authentication](https://dependencywatch.io/package/npm/rxnt-authentication) | npm | 0.0.3, 0.0.4, 0.0.5, 0.0.6 |
| [rxnt-healthchecks-nestjs](https://dependencywatch.io/package/npm/rxnt-healthchecks-nestjs) | npm | 1.0.2, 1.0.3, 1.0.4, 1.0.5 |
| [rxnt-kue](https://dependencywatch.io/package/npm/rxnt-kue) | npm | 1.0.4, 1.0.5, 1.0.6, 1.0.7 |
| [swc-plugin-component-annotate](https://dependencywatch.io/package/npm/swc-plugin-component-annotate) | npm | 1.9.1, 1.9.2 |
| [tbssnch](https://dependencywatch.io/package/npm/tbssnch) | npm | 1.0.2 |
| [teselagen-interval-tree](https://dependencywatch.io/package/npm/teselagen-interval-tree) | npm | 1.1.2 |
| [tg-client-query-builder](https://dependencywatch.io/package/npm/tg-client-query-builder) | npm | 2.14.4, 2.14.5 |
| [tg-redbird](https://dependencywatch.io/package/npm/tg-redbird) | npm | 1.3.1, 1.3.2 |
| [tg-seq-gen](https://dependencywatch.io/package/npm/tg-seq-gen) | npm | 1.0.9, 1.0.10 |
| [thangved-react-grid](https://dependencywatch.io/package/npm/thangved-react-grid) | npm | 1.0.3 |
| [ts-gaussian](https://dependencywatch.io/package/npm/ts-gaussian) | npm | 3.0.5, 3.0.6 |
| [ts-imports](https://dependencywatch.io/package/npm/ts-imports) | npm | 1.0.1, 1.0.2 |
| [tvi-cli](https://dependencywatch.io/package/npm/tvi-cli) | npm | 0.1.5 |
| [ve-bamreader](https://dependencywatch.io/package/npm/ve-bamreader) | npm | 0.2.6, 0.2.7 |
| [ve-editor](https://dependencywatch.io/package/npm/ve-editor) | npm | 1.0.1, 1.0.2 |
| [verror-extra](https://dependencywatch.io/package/npm/verror-extra) | npm | 6.0.1 |
| [voip-callkit](https://dependencywatch.io/package/npm/voip-callkit) | npm | 1.0.2, 1.0.3 |
| [wdio-web-reporter](https://dependencywatch.io/package/npm/wdio-web-reporter) | npm | 0.1.3 |
| [yargs-help-output](https://dependencywatch.io/package/npm/yargs-help-output) | npm | 5.0.3 |
| [yoo-styles](https://dependencywatch.io/package/npm/yoo-styles) | npm | 6.0.326 |

## What happened

Shai-Hulud is the first publicly-confirmed self-propagating worm in the npm ecosystem. It descends directly from the August 2025 `s1ngularity` / Nx GitHub-token theft: a researcher leaked Personal Access Tokens from contributors to the `nrwl/nx` repo, and those tokens were used a month later to seed the worm into reachable maintainer accounts.

The payload runs from a `postinstall` hook. It uses `TruffleHog` to scan the host for any credentials it can find - npm tokens, GitHub PATs, AWS/GCP/Azure keys, anything matching a known secret pattern - then performs three propagation moves: it creates a public GitHub repo named **"Shai-Hulud"** containing the stolen secrets, force-converts private repos belonging to the victim to public with a `-migration` suffix, and uses the stolen npm tokens to push new malicious versions of every package the maintainer can publish to.

Around 180 unique packages were compromised across 300+ versions before npm and GitHub coordinated takedowns. High-blast-radius hits included `@ctrl/tinycolor`, `ngx-bootstrap`, `ngx-toastr`, and - notably - the entire `@crowdstrike/*` scope, which forced an internal incident response at CrowdStrike. The worm continued to surface in mini-revivals through early 2026 (see `multi-2026-04-30-mini-shai-hulud-wave2` and `npm-2026-05-shai-hulud-tanstack`).

If you built anything against an affected package between September 15 and 18, 2025, treat the host as credential-compromised: rotate every secret reachable from that environment, then audit the GitHub org for unexpected public repos and `-migration` twins.

## Impact

- TruffleHog-driven secret discovery on dev/CI machines
- Public exposure of private repositories ("-migration" rename pattern)
- Stolen-credential propagation to any reachable npm package
- Malicious GitHub Actions workflows for repository-secret exfil
- High-blast-radius packages hit: @ctrl/tinycolor, ngx-bootstrap, ngx-toastr, @crowdstrike/*

## What to do

1. Rotate npm + GitHub tokens used in any environment that resolved affected versions
2. Audit your GitHub org for public repos created under your account or with "Shai-Hulud" in the name
3. Review private repos for unexpected "-migration" public twins
4. Investigate any unexpected publish activity on packages you own
5. For projects using @crowdstrike/* scopes, treat any host that built after 15 Sept 2025 as suspect until verified

## 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

- [Wiz: Shai-Hulud npm supply-chain attack](https://www.wiz.io/blog/shai-hulud-npm-supply-chain-attack) - Wiz
- [Socket: Shai-Hulud worm spreading via npm](https://socket.dev/blog/ongoing-supply-chain-attack-targets-crowdstrike-npm-packages) - Socket
- [StepSecurity: ctrl/tinycolor and 40+ packages compromised](https://www.stepsecurity.io/blog/ctrl-tinycolor-and-40-npm-packages-compromised) - StepSecurity

---

Canonical page: https://dependencywatch.io/incident/npm-2025-09-shai-hulud-original
Markdown version: https://dependencywatch.io/incident/npm-2025-09-shai-hulud-original.md
Site index for agents: https://dependencywatch.io/llms.txt
DependencyWatch.io is operated by Precursor Security (https://precursorsecurity.com).
