Updated: Sept. 17, 2025
Introduction
Node Package Manager (NPM) is the default package manager for JavaScript and Node.js. It allows developers to share, download, and integrate reusable bits of code called packages. These packages form the backbone of modern software development: from small utilities like string formatting to large frameworks powering web applications. But with this convenience comes risk. When attackers compromise an NPM package, the impact can cascade across thousands of applications worldwide. The latest NPM compromise involving popular packages like debug, chalk and later expanding to over 180 packages (as of Sept. 17, 2025) highlights why supply chain security is one of the biggest concerns for developers and enterprises today.
Recent Compromise
In September 2025, attackers successfully compromised 18 widely used NPM packages, including debug, chalk, ansi-styles, and strip-ansi. These packages collectively have billions of weekly downloads. The attack began with a phishing campaign targeting a package maintainer. The phishing email, impersonating an NPM support request, tricked the maintainer into revealing credentials, allowing attackers to publish malicious versions of these packages.
The malicious code injected into these versions was sophisticated:
- It wrapped browser APIs like fetch and XMLHttpRequest.
- It intercepted calls to crypto wallets and Web3 APIs.
- It aimed to steal or redirect cryptocurrency transactions.
The compromised versions were live for approximately two hours before being detected and rolled back, but that was enough for some developers and CI/CD pipelines to pull in the malicious code.
Escalation: S1ngularity/nx and the Worm Campaign
A week after the initial compromise, researchers observed a second wave of attacks by the same group, tracked as S1ngularity/nx. This time, the scope was much larger and included:
- 187 packages compromised in total (40 initially, then 147 more).
- Malware evolved into a worm (“Shai-Hulud”) with advanced propagation features.
- Capabilities included:
- Harvesting secrets from environment variables, .npmrc files, and cloud metadata endpoints.
- Using tools like TruffleHog to scrape sensitive data.
- Exfiltrating secrets into malicious GitHub repositories.
- Injecting malicious GitHub Actions workflows for persistence and spread.
- Flipping private GitHub repos to public to expose sensitive data.
This evolution shows the shift from a targeted compromise to a self-propagating supply chain worm.

Fig. 1: Timeline of the September 2025 NPM compromises – escalating from a short-lived package hijack to a worm-level supply chain campaign.
Impact
CrowdStrike-maintained NPM packages were impacted in this campaign. This is a significant escalation because it shows attackers are not only targeting hobby or low-maintenance libraries, but also trusted security vendors’ packages. The compromise of packages such as @crowdstrike/commitlint, @crowdstrike/falcon-shoelace, and @crowdstrike/foundry-js demonstrates that no ecosystem participant is immune, and emphasizes the need for constant vigilance, supply chain monitoring, and third-party validation.
CrowdStrike stated that after detecting malicious NPM packages, they swiftly removed them, rotated their keys in public registries, and confirmed that Falcon sensor was not impacted and customers remain protected while a thorough investigation is ongoing.
The incident has caused alarm across the developer community and enterprise security teams because:
- Massive Reach: Popular packages like debug and chalk are dependencies in thousands of projects.
- Transitive Risk: Even if your app doesn’t depend on the affected package directly, a downstream dependency might.
- Financial Risk: With targeting of crypto wallets, the potential for theft and fraud is immediate.
- Trust Erosion: Developers trust package maintainers and registries; a compromise undermines this trust model.
- Worm Propagation: Unlike the first wave, the Shai-Hulud malware could autonomously spread, escalating impact.
This is why discussions around supply chain attacks via NPM are not just technical, they affect business outcomes, security, and reputation.
Technical Details
Affected Packages and Versions
While the full list is evolving, here are some confirmed compromised packages:
- ansi-styles
- debug
- backslash
- chalk-template
- supports-hyperlinks
- has-ansi
- simple-swizzle
- color-string
- error-ex
- color-name
- is-arrayish
- slice-ansi
- color-convert
- wrap-ansi
- ansi-regex
- supports-color
- strip-ansi
- chalk
Later waves extended this list to 187 packages, including libraries tied to frontend tooling, color utilities, and even packages linked to CrowdStrike dependencies. The malicious versions were published around Sept 8, 2025 (first wave) and Sept 16, 2025 (worm campaign). If your builds occurred during these timeframes, you may have been impacted.
Extended Affected Packages:
| Package | Versions |
| @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 | 2.0.28, 2.0.32 |
| @art-ws/di-node | 2.0.13 |
| @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.9, 0.1.12 |
| @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.9, 1.0.10 |
| @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/deluge | 7.2.1, 7.2.2 |
| @ctrl/golang-template | 1.4.2, 1.4.3 |
| @ctrl/magnet-link | 4.0.3, 4.0.4 |
| @ctrl/ngx-codemirror | 7.0.1, 7.0.2 |
| @ctrl/ngx-csv | 6.0.1, 6.0.2 |
| @ctrl/ngx-emoji-mart | 9.2.1, 9.2.2 |
| @ctrl/ngx-rightclick | 4.0.1, 4.0.2 |
| @ctrl/qbittorrent | 9.7.1, 9.7.2 |
| @ctrl/react-adsense | 2.0.1, 2.0.2 |
| @ctrl/shared-torrent | 6.3.1, 6.3.2 |
| @ctrl/tinycolor | 4.1.1, 4.1.2 |
| @ctrl/torrent-file | 4.1.1, 4.1.2 |
| @ctrl/transmission | 7.3.1 |
| @ctrl/ts-base32 | 4.0.1, 4.0.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/gesturehandler | 2.0.35 |
| @nativescript-community/perms | 3.0.5, 3.0.6, 3.0.7, 3.0.8 |
| @nativescript-community/sqlite | 3.5.2, 3.5.3, 3.5.4, 3.5.5 |
| @nativescript-community/text | 1.6.9, 1.6.10, 1.6.11, 1.6.12 |
| @nativescript-community/typeorm | 0.2.30, 0.2.31, 0.2.32, 0.2.33 |
| @nativescript-community/ui-collectionview | 6.0.6 |
| @nativescript-community/ui-document-picker | 1.1.27, 1.1.28 |
| @nativescript-community/ui-drawer | 0.1.30 |
| @nativescript-community/ui-image | 4.5.6 |
| @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-bottomsheet | 7.2.72 |
| @nativescript-community/ui-material-core | 7.2.72, 7.2.73, 7.2.74, 7.2.75 |
| @nativescript-community/ui-material-core-tabs | 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 | 20.0.4 |
| @nstudio/web-angular | 20.0.4 |
| @nstudio/xplat | 20.0.5, 20.0.6, 20.0.7 |
| @nstudio/xplat-utils | 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 |
| @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 |
| @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 |
| @teselagen/bounce-loader | 0.3.16, 0.3.17 |
| @teselagen/liquibase-tools | 0.4.1 |
| @teselagen/range-utils | 0.3.14, 0.3.15 |
| @teselagen/react-list | 0.8.19, 0.8.20 |
| @teselagen/react-table | 6.10.19 |
| @thangved/callback-window | 1.1.4 |
| @things-factory/attachment-base | 9.0.43, 9.0.44, 9.0.45, 9.0.46, 9.0.47, 9.0.48, 9.0.49, 9.0.50 |
| @things-factory/auth-base | 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 |
| @things-factory/env | 9.0.42, 9.0.43, 9.0.44, 9.0.45 |
| @things-factory/integration-base | 9.0.43, 9.0.44, 9.0.45 |
| @things-factory/integration-marketplace | 9.0.43, 9.0.44, 9.0.45 |
| @things-factory/shell | 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 |
| angulartics2 | 14.1.1, 14.1.2 |
| 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 | 1.1.2, 1.1.3 |
| ember-headless-form-yup | 1.0.1 |
| 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 |
| encounter-playground | 0.0.2, 0.0.3, 0.0.4, 0.0.5 |
| eslint-config-crowdstrike | 11.0.2, 11.0.3 |
| eslint-config-crowdstrike-node | 4.0.3, 4.0.4 |
| eslint-config-teselagen | 6.1.7 |
| globalize-rpk | 1.7.4 |
| graphql-sequelize-teselagen | 5.3.8 |
| html-to-base64-image | 1.0.2 |
| json-rules-engine-simplified | 0.2.1 |
| jumpgate | 0.0.2 |
| koa2-swagger-ui | 5.11.1, 5.11.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 |
| ng2-file-upload | 7.0.2, 7.0.3, 8.0.1, 8.0.2, 8.0.3, 9.0.1 |
| ngx-bootstrap | 18.1.4, 19.0.3, 19.0.4, 20.0.3, 20.0.4, 20.0.5 |
| ngx-color | 10.0.1, 10.0.2 |
| ngx-toastr | 19.0.1, 19.0.2 |
| ngx-trend | 8.0.1 |
| ngx-ws | 1.1.5, 1.1.6 |
| oradm-to-gql | 35.0.14, 35.0.15 |
| oradm-to-sqlz | 1.1.2 |
| ove-auto-annotate | 0.0.9 |
| pm2-gelf-json | 1.0.4, 1.0.5 |
| printjs-rpk | 1.6.1 |
| react-complaint-image | 0.0.32 |
| react-jsonschema-form-conditionals | 0.3.18 |
| remark-preset-lint-crowdstrike | 4.0.1, 4.0.2 |
| rxnt-authentication | 0.0.3, 0.0.4, 0.0.5, 0.0.6 |
| rxnt-healthchecks-nestjs | 1.0.2, 1.0.3, 1.0.4, 1.0.5 |
| rxnt-kue | 1.0.4, 1.0.5, 1.0.6, 1.0.7 |
| swc-plugin-component-annotate | 1.9.1, 1.9.2 |
| tbssnch | 1.0.2 |
| teselagen-interval-tree | 1.1.2 |
| tg-client-query-builder | 2.14.4, 2.14.5 |
| tg-redbird | 1.3.1 |
| tg-seq-gen | 1.0.9, 1.0.10 |
| thangved-react-grid | 1.0.3 |
| ts-gaussian | 3.0.5, 3.0.6 |
| ts-imports | 1.0.1, 1.0.2 |
| tvi-cli | 0.1.5 |
| ve-bamreader | 0.2.6 |
| ve-editor | 1.0.1 |
| 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 |
Check To Verify If You’ve Been Affected
- Inspect Dependency Trees: Run npm ls or yarn list to see if your project uses any affected packages.
- Check Lockfiles: Review package-lock.json, yarn.lock, or pnpm-lock.yaml for references to the bad versions.
- Search CI/CD Logs: Look for builds that ran during the compromise window.
- Audit Bundles: For frontend applications, scan-built JavaScript bundles to see if compromised code is included.
- Use SBOMs: If you generate a Software Bill of Materials (SBOM), search it for affected versions.
- Check GitHub Repos: Validate if any repositories had suspicious workflow files, unexpected commits, or suddenly flipped to public.
Hunting Queries
Below are sample queries you can use as starting points to proactively search for malicious activity. When using these remember to:
- Treat these as templates, replace indexes, table names, and field names to match your environment.
- Create a package watchlist / lookup file :
- Maintain a controlled list of affected package names and version patterns in a central lookup or watchlist. This makes it easy to update detection rules when new packages are added and avoids repeatedly editing queries.
In CI/CD Environments:
In SIEM & EDR:
KQL
SPL
Yara-L
CS
S1
Real-World Detection Example
Using Splunk, we ran a targeted query against web proxy logs to detect downloads of the compromised NPM package versions. The query matched on specific package names and version patterns associated with the September 2025 attack.

Fig. 1: Detection of malicious NPM package versions in Splunk web proxy logs
Detections observed included:
- strip-ansi@7.1.1
- ansi-regex@6.2.1
- ansi-styles@6.2.2
- debug@4.4.2
- error-ex@1.3.3
These events were logged as downloads from registry.npmjs.org over port 443. The results provided visibility into which hosts and IP addresses in the environment had pulled malicious packages.
Action Items:
- Confirm whether the packages were included in builds.
- Investigate if developers or CI/CD agents pulled the versions.
- Hunt for subsequent execution of malicious JavaScript payloads.
This case demonstrates the importance of monitoring both package downloads and runtime behaviors.
SOC Observations:
When the above detections were validated in Microsoft Defender for Endpoint (MDE):
- DeviceNetworkEvents showed connections to registry.npmjs.org, but there were no DeviceFileEvents confirming persistence of the malicious packages.
- The impacted host was identified as a Git-runner, which installs dependencies during builds and then deletes them, explaining the absence of file artifacts.
- Analysts observed some npm install –ignore-scripts activity, but it occurred prior to the compromise and did not include vulnerable versions.
Key takeaway: In CI/CD and build environments, malicious dependencies may not leave behind file traces. Defenders should focus on network telemetry, installation logs, and package resolution events when hunting for supply chain compromises.
Recommendations
Recommendations for mitigation and prevention include:
- Upgrade Immediately: Update to the latest safe versions released after the compromise.
- Audit Pipelines: Ensure builds during the compromise window are redeployed with clean dependencies.
- Enable 2FA: Maintainers should enforce strong MFA to prevent phishing-based account takeovers.
- Pin Dependencies: Use exact version pinning in lockfiles.
- Generate and Monitor SBOMs: Helps quickly identify impacted builds.
- Monitor GitHub Activity: Watch for unexpected workflow file changes or repos flipping public.
- Use Trusted Registries: Mirror or proxy registries with malware scanning.
Indicators of Compromise
File Hashes:
- Malicious bundle.js SHA-256: 46faab8ab153fae6e80e7cca38eab363075bb524edd79e42269217a083628f09
- de0e25a3e6c1e1e5998b306b7141b3dc4c0088da9d7bb47c1c00c91e6e4f85d6
- 81d2a004a1bca6ef87a1caf7d0e0b355ad1764238e40ff6d1b1cb77ad4f595c3
- 83a650ce44b2a9854802a7fb4c202877815274c129af49e6c2d1d5d5d55c501e
- 4b2399646573bb737c4969563303d8ee2e9ddbd1b271f1ca9e35ea78062538db
- dc67467a39b70d1cd4c1f7f7a459b35058163592f4a9e8fb4dffcbba98ef210c
- 46faab8ab153fae6e80e7cca38eab363075bb524edd79e42269217a083628f09
- b74caeaa75e077c99f7d44f46daaf9796a3be43ecf24f2a1fd381844669da777
Network Indicators:
- Exfiltration endpoint: https://webhook.site/bb8ca5f6-4175-45d2-b042-fc9ebb8170b7
File System Indicators:
- Presence of malicious workflow file: .github/workflows/shai-hulud-workflow.yml
Suspicious Function Calls:
- NpmModule.updatePackage
Suspicious API Calls:
- AWS Secrets Manager: secretsmanager.*.amazonaws.com (esp. BatchGetSecretValueCommand)
- GCP: secretmanager.googleapis.com
- NPM Registry: registry.npmjs.org/v1/search
- GitHub API: api.github.com/repos
Suspicious Process Executions:
- TruffleHog execution with filesystem / arguments
- npm publish –force commands
- curl calls to webhook.site domains
Conclusion
The September 2025 NPM compromises are a reminder of the fragility of modern software supply chains. What began as a two-hour malicious package injection escalated into a worm-level campaign capable of harvesting secrets and spreading across ecosystems.
By auditing dependencies, monitoring builds, analyzing GitHub activity, and strengthening package security practices, developers and enterprises can reduce risk. But vigilance is key, supply chain attacks will remain one of the most dangerous vectors in software security.











