• Blog
  • “Shai-Hulud” npm Attack: What You Need to Know

Blog

“Shai-Hulud” npm Attack: What You Need to Know

Get details on this supply chain attack.

What Happened?

On September 15-16, 2025, malicious versions of multiple npm packages were published. The packages included a post-install script designed to harvest secrets (environment variables, credentials) and exfiltrate them to an attacker-controlled GitHub repository named Shai-Hulud.

The attack goes beyond data exfiltration; it involves worm-like behavior. If a compromised package is installed in an environment with accessible npm tokens, it will attempt to publish malicious versions of other packages owned by the same maintainer — spreading the compromise.

The campaign is believed to be downstream of a previous incident (the s1ngularity / Nx compromise): attacker(s) stole GitHub tokens, then used them to steal npm tokens and escalate to widespread package poisoning.

 

Who Is Affected? 

The primary victims are developers and organizations that unknowingly installed or built with the malicious npm package versions published during the attack window, before they were removed from the registry. This includes anyone who:

  • Installed the tainted packages directly.
  • Consumed them indirectly through transitive dependencies in their CI/CD pipelines.

 

What Is the Threat?  

The central danger of this campaign lies in the exposure of secrets and credentials. Once the malicious post-install scripts were executed, they attempted to harvest sensitive tokens and keys from the environment, including:

  • GitHub PATs – which could allow attackers to clone private repositories, inject malicious workflows, change repo visibility, or exfiltrate additional secrets
  • npm tokens – enabling attackers to release new malicious versions of packages under a trusted maintainer’s namespace, continuing the worm-like propagation of the attack
  • Cloud service credentials (AWS, GCP, Azure, etc.) – potentially granting access to production systems, storage buckets, databases, or other sensitive infrastructure

The theft of these credentials opens the door to long-term compromise, even after the malicious npm packages are removed. Attackers with valid secrets can:

  • Push additional malicious code updates to affected repositories or packages.
  • Leak or destroy sensitive source code and intellectual property.
  • Escalate into cloud environments, where they can exfiltrate data, deploy cryptominers, or cause broader service outages.

In other words, the true risk extends beyond the initial package compromise—it is the persistent foothold attackers can maintain through stolen credentials across a victim’s software supply chain and cloud infrastructure.

 

What Should Your Organization Do?

Organizations should take the following actions:

  1. Check your inventory for vulnerable dependencies affected by the attack.
  2. Remove or roll back compromised package versions and rebuild all affected projects from a clean source or artifact repository.
  3. Revoke and rotate all credentials that may have been exposed on impacted developer machines or CI/CD runners. This includes npm tokens, GitHub PATs, and any cloud service keys.
  4. Review audit and access logs for unusual activity such as unexpected installs, unauthorized package publications, or the creation of suspicious GitHub workflow files.
  5. Inspect your GitHub account for a repository named “Shai-Hulud.” The malware automatically creates this repo to store exfiltrated secrets. If it exists, remove it immediately, and carefully review its history and contents to understand what data may have been leaked.

Use Legit to Protect Your Organization  

Legit secrets scanning, which prevent secrets exposure in the SDLC, would have significantly reduced the risk posed by this attack. In addition, the Legit secrets scanner helps identify which secrets should be revoked, even if they were exposed, as quickly as possible.

Another challenge is to determine whether your organization was infected. Legit can help you do this both by providing a comprehensive dependencies inventory and SCA scanning to determine whether your organization uses the vulnerable packages and help you act accordingly.

For more details, contact your Legit customer support representative, or contact us.

 

Known impacted packages 

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

 

 

 

Share this guide

Published on
September 18, 2025

Get a stronger AppSec foundation you can trust and prove it’s doing the job right.

Request a Demo