On 4 November 2021, attackers used a compromised npm developer account to publish malicious versions of two widely used JavaScript packages, coa, a command-line argument parser, and rc, a configuration loader. Together they had about 23 million weekly downloads, according to The Record. Neither package had seen a legitimate release in years, so the sudden new versions were pulled straight into builds, and coa's broke React build pipelines around the world. The new versions ran a preinstall script that downloaded a Windows DLL identified as a password-stealing trojan. npm disabled the compromised account, removed all the malicious versions within hours and told users to treat affected machines as fully compromised. The malicious code was almost identical to that used against ua-parser-js thirteen days earlier. Eleven days later GitHub named coa, rc and ua-parser-js when it announced mandatory two-factor authentication for maintainers of popular npm packages. How the account was compromised has not been disclosed.
Key takeaways
- Malicious coa versions 2.0.3, 2.0.4, 2.1.1, 2.1.3, 3.0.1 and 3.1.3 and rc versions 1.2.9, 1.3.9 and 2.3.9 were published on 4 November 2021, according to GitHub's advisories.
- The releases came from a compromised developer account with publishing rights, which npm disabled; coa had about 8.8 million and rc about 14.2 million weekly downloads, according to The Record.
- A preinstall script fetched a DLL that BleepingComputer assessed as the Danabot password stealer; The Record reported Qakbot detections. Either way, the target was credentials on developer and build machines.
- npm removed the malicious versions within hours; the code closely matched the ua-parser-js hijack of 22 October, and GitHub cited both when it announced 2FA enforcement on 15 November 2021.
- The identity lesson: dormant packages keep live publishing rights, and an unused publishing identity with weak protection is an open door into every project that depends on it.
At a glance
| Organisations | The coa and rc npm packages and the developers and organisations that installed them |
|---|---|
| When | 4 November 2021; malicious versions removed the same day |
| Attacker | Unknown; the code was almost identical to the ua-parser-js hijack of October 2021, according to The Record |
| Entry point | A compromised npm developer account with publishing rights for coa and rc |
| Identities abused | npm publishing rights for coa and rc; passwords and credentials on machines that installed the malicious versions |
| Impact | Nine malicious releases delivering a password-stealing trojan on Windows; React build pipelines broken worldwide |
| Category | NHI. Incident class: confirmed NHI breach (hijacked npm publishing account used to ship credential-stealing malware) |
What happened
coa and rc are small, old utilities buried deep in the JavaScript dependency tree. coa had not had a legitimate release since December 2018 and rc since December 2015, according to The Record, but both were still pulled in by many projects, including build tooling used by React applications. On 4 November 2021, new coa versions began appearing on npm within hours of each other. Developers noticed because builds started failing. "Whatever this release did, it broke the internet," developer Roberto Wesley Overdijk wrote, as quoted by BleepingComputer.
BleepingComputer analysed the coa releases. A preinstall script ran a file called compile.js, which launched an obfuscated compile.bat, which downloaded and ran a DLL named sdd.dll from a remote domain. BleepingComputer assessed that "the malware is likely the Danabot password-stealing Trojan for Windows", able to steal browser passwords, application credentials and stored payment cards. The Record reported that Windows Defender and other engines detected a version of the Qakbot trojan in the DLL. Hours later, npm found the same problem in rc: "we identified in real time multiple versions of the 'rc' package containing identical malware," it said, according to BleepingComputer.
npm blamed a compromised developer account. "The compromised [developer] account has been temporarily disabled," it said, adding "we are actively investigating the incident and monitoring for similar activity," according to The Record. npm removed every malicious version. GitHub's advisories listed six bad coa versions and three bad rc versions, told users to go back to coa 2.0.2 and rc 1.2.8, and warned that any machine that installed or ran the packages should be considered fully compromised, with all secrets and keys rotated from a different computer.
The Record noted that the malicious code was "almost identical to the one used in the compromise of the UAParser library", the ua-parser-js hijack of 22 October. On 15 November, GitHub's chief security officer Mike Hanley wrote: "Examples include the recent takeovers of the ua-parser-js, coa, and rc packages." He said some takeovers had involved accounts without two-factor authentication and that GitHub would require 2FA for maintainers of top packages from the first quarter of 2022. How the coa and rc account was compromised has not been made public.
Timeline
| Date | Event |
|---|---|
| 22 October 2021 | ua-parser-js is hijacked with closely matching malicious code. |
| 4 November 2021 | Malicious coa versions appear on npm and break React build pipelines; rc versions with the same malware follow hours later. |
| 4 November 2021 | npm disables the compromised account and removes the versions; GitHub publishes advisories for coa and rc. |
| 5 November 2021 | The Record reports both hijacks and the combined 23 million weekly downloads. |
| 15 November 2021 | GitHub cites coa, rc and ua-parser-js and announces 2FA enforcement for top npm maintainers from 2022. |
How it happened: the identity attack path
- Dormant publishing rights. A developer account kept the right to publish coa and rc, packages that had not had a legitimate release for three and six years respectively.
- Account compromise. Attackers gained access to that npm account; npm has not said how.
- Malicious releases. The attackers published nine new versions across both packages, which version ranges in downstream projects accepted automatically.
- Install-time execution. A preinstall script ran compile.js and compile.bat, which fetched and ran a password-stealing DLL on Windows machines.
- Credential theft and response. The malware targeted stored passwords and credentials; npm disabled the account and removed the versions, and users were told to rotate all secrets on affected machines.
Impact
- Confirmed: nine malicious releases of two packages with about 23 million combined weekly downloads were published and removed on 4 November 2021.
- Disruption: builds of React applications and other projects failed worldwide while the malicious coa versions were live.
- Credentials at risk: passwords, application credentials and other secrets on Windows machines that ran the malware, including developer and CI credentials stored there.
- Not known: how many machines executed the payload, and whether stolen credentials were later used; no source reports either.
What this means for NHI and AI agent security
A package publishing account is a non-human identity in function: it is how the registry decides which code downstream builds will trust and run. For coa and rc, that identity had been idle for years, yet it still held full publishing rights over packages with millions of weekly downloads. Nobody was watching it, and the first sign of trouble was broken builds around the world. We class the incident as an NHI breach for that reason, and because the payload went after the credentials sitting on developer and build machines.
The fix is partly the registry's and partly every consumer's. Registries now push 2FA and trusted publishing from CI. Consumers can pin versions, delay adoption of brand-new releases, block install scripts and keep long-lived credentials off machines that run untrusted code. The eslint-scope compromise of 2018 and the Shai-Hulud worm show the same identity failure at different scales. See our CI/CD Pipeline Identity Security Guide and NHI Ownership Guide.
Recommendations
- Rotate every secret on machines that installed a malicious version. Treat them as fully compromised, rebuild them and rotate credentials from a clean computer. See the Leaked Credential Response Playbook.
- Review and remove dormant publishing rights. Maintainers of inactive packages should drop unused collaborators and tokens, and registries should flag publishing from long-idle accounts. See our NHI Ownership Guide.
- Require strong MFA and short-lived tokens for publishing. Publishing from CI through trusted publishing removes long-lived personal tokens altogether. See our MFA Guide.
- Pin dependencies and slow down new releases. Lockfiles and a minimum release age would have kept a brand-new release of a six-year-old package out of builds.
- Block install scripts by default. Allow preinstall and postinstall scripts only for packages that need them.
- Keep credentials out of build environments that run third-party code. Inject short-lived secrets only into the steps that need them. See our CI/CD Pipeline Identity Security Guide.
Frequently asked questions
Which coa and rc versions were malicious?
According to GitHub's advisories, coa 2.0.3, 2.0.4, 2.1.1, 2.1.3, 3.0.1 and 3.1.3 and rc 1.2.9, 1.3.9 and 2.3.9. The advice was to go back to coa 2.0.2 and rc 1.2.8 and treat any machine that ran the bad versions as fully compromised.
What malware was in the coa and rc packages?
A preinstall script downloaded a Windows DLL that BleepingComputer assessed as the Danabot password-stealing trojan; The Record reported that Windows Defender and others detected a Qakbot version. Both are designed to steal credentials from infected machines.
Are the coa and rc hijacks linked to ua-parser-js?
The Record found the malicious code almost identical to that used in the ua-parser-js hijack of 22 October 2021, and GitHub named all three as recent npm account takeovers. No source has publicly attributed them to a named attacker.
Related NHI Mgmt Group resources
ua-parser-js npm Hijack 2021 · eslint-scope npm Compromise 2018 · ChainDrop npm Worm 2026 · CI/CD Pipeline Identity Security Guide · NHI Ownership Guide
How NHI Mgmt Group can help
Old packages with live publishing rights are a quiet risk in every software supply chain. We help teams map who and what can publish the code they depend on, remove dormant access and prepare the credential rotation that a malicious dependency demands. See our NHI and AI agent security training.
References
- GitHub Advisory Database: Embedded malware in coa (4 November 2021)
- GitHub Advisory Database: Embedded malware in rc (4 November 2021)
- BleepingComputer: Popular 'coa' NPM library hijacked to steal user passwords (4 November 2021)
- The Record: Malware found in coa and rc, two npm packages with 23M weekly downloads (5 November 2021)
- GitHub: GitHub's commitment to npm ecosystem security (15 November 2021)