Exec Summary
Malicious releases of @ctrl/tinycolor (4.1.1, 4.1.2)
were published to npm as part of a broader campaign that trojanized 40+ packages across multiple maintainers.
The payload is a bundled controller (bundle.js
) that runs on install, harvests developer/CI credentials, and self-propagates by automatically modifying and republishing other packages owned by compromised maintainers. The malicious versions have since been removed from npm.
There are strong indications this is from the same threat actor as the Nx compromise from a few weeks ago. This likely means that credentials, access, and persistence are their immediate goals, but there will be cascading impacts over the next few days/weeks.
Technical Breakdown
Execution vector
The compromised packages include a change that causes bundle.js
to run during installation (commonly via postinstall). From there, it drives a multi-stage routine.
Credential Harvesting
The controller profiles the host and invokes TruffleHog to sweek local filesystems for high-entropy secrets, while also directly probing environment variables and cloud metadata.
It targets npm, GitHub, and major cloud providers (AWS/Azure/GCP). Findings are exfiltrated to a hard-coded webhook[.]site endpoint.
Persistence and Blast Radius
If GitHub token is present, the malware writes a workflow file (.github/workflows/shai-hulud-workflow.yml)
into repos to exfiltrate secrets on future pushes.
Self-propagation
A function often described as NpmModule.updatePackage
downloads a maintainer’s other packages, injects bundle.js
, repacks, and republishes, enabling a worm-like spread across the maintainer’s portfolio
OS Targeting
Analyses indicate a primary focus on Linux/macOS developer and CI agents. However, other endpoints may still be impacted.
Immediate Actions
- Triage & Contain - Search for affected versions, remove/downgrade to known-good. Pin and rebuild images.
- Rotate credentials - Any developer/CI hosts that had the impacted version installed must be rotated. This should include, but may not be limited to:
- npm tokens
- GitHub PATs/Action secrets
- Cloud credentials (AWS/Azure/GCP)
- Corporate credentials if stored locally
- Any credentials stored in plaintext on impacted systems
- Hunt for Persistence - Grep repos/orgs for
.github/workflows/shai-hulud-workflow.yml
. Review recent npm publish events and unexpected package.json edits. Monitor egress towebhook.site
indicators. - Strengthen Publisher Hygiene - Enforce MFA for login and PRs, and scoped, short-lived published tokens. Run pre-publish checks. Monitor for anomalous postinstall/networking deltas in diffs (Ossprey can help!)
Affected Packages
Package Name | Version(s) |
---|---|
@ctrl/tinycolor | 4.1.1, 4.1.2 |
angulartics2 | 14.1.2 |
@ctrl/deluge | 7.2.2 |
@ctrl/golang-template | 1.4.3 |
@ctrl/magnet-link | 4.0.4 |
@ctrl/ngx-codemirror | 7.0.2 |
@ctrl/ngx-csv | 6.0.2 |
@ctrl/ngx-emoji-mart | 9.2.2 |
@ctrl/ngx-rightclick | 4.0.2 |
@ctrl/qbittorrent | 9.7.2 |
@ctrl/react-adsense | 2.0.2 |
@ctrl/shared-torrent | 6.3.2 |
@ctrl/torrent-file | 4.1.2 |
@ctrl/transmission | 7.3.1 |
@ctrl/ts-base32 | 4.0.2 |
encounter-playground | 0.0.5 |
json-rules-engine-simplified | 0.2.4, 0.2.1 |
koa2-swagger-ui | 5.11.2, 5.11.1 |
@nativescript-community/gesturehandler | 2.0.35 |
@nativescript-community/sentry | 4.6.43 |
@nativescript-community/text | 1.6.13 |
@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 |
@nativescript-community/ui-material-core-tabs | 7.2.76 |
ngx-color | 10.0.2 |
ngx-toastr | 19.0.2 |
ngx-trend | 8.0.1 |
react-complaint-image | 0.0.35 |
react-jsonschema-form-conditionals | 0.3.21 |
react-jsonschema-form-extras | 1.0.4 |
rxnt-authentication | 0.0.6 |
rxnt-healthchecks-nestjs | 1.0.5 |
rxnt-kue | 1.0.7 |
swc-plugin-component-annotate | 1.9.2 |
ts-gaussian | 3.0.6 |
@crowdstrike/commitlint | |
@crowdstrike/falcon-shoelace | |
@crowdstrike/foundry-js | |
@crowdstrike/glide-core | |
@crowdstrike/logscale-dashboard | |
@crowdstrike/logscale-file-editor | |
@crowdstrike/logscale-parser-edit | |
@crowdstrike/logscale-search | |
@crowdstrike/tailwind-toucan-base |
NOTE: the list of impacted packages is growing. Please continue to check in here for the lastest list of impacted resources
IOCs
- Filename:
bundle.js
(SHA-256:46faab8ab153fae6e80e7cca38eab363075bb524edd79e42269217a083628f09
) - Exfil endpoint:
https://webhook[.]site/bb8ca5f6-4175-45d2-b042-fc9ebb8170b7
- Maliciuos workflow path:
.github/workflows/shai-hulud-workflow.yml
How Ossprey Can Help!
Map maintainer and transitive risk.
Generate and continuously reconcile SBOMs to link packages to maintainers and orgs, surface owner pivots, and flag risky transitive chains before they reach builds.
Detect malicious updates early
Ossprey’s behavior-first scanners diff new releases, de-obfuscate bundled assets, and spot install-time scripts, credential harvesting, beaconing, and self-publish routines in near-real time.
Protect every pull request
Seamless CI/CD integrations silently enforce provenance and block suspect packages by default, quarantining risky changes and guiding remediation before merge.
Get Ossprey protection now! Sign up to our wait list, or contact us directly at contact@ossprey.com