rc and coa Coordinated npm Account Takeover (2021)
Two long-unmaintained npm packages — rc and coa, with combined weekly downloads in the tens of millions — were hijacked the same day and shipped credential-harvesting payloads matching ua-parser-js.
Summary
On November 4, 2021 — roughly two weeks after the ua-parser-js compromise — two more long-dormant npm packages were hijacked in rapid succession: coa (a command-line option parser used as a transitive dependency by the Angular and React CLI ecosystems) and rc (a configuration loader used in roughly 14 million weekly downloads). Both received malicious patch versions carrying a credential-stealing payload nearly identical to the ua-parser-js attack. The two takeovers happened within hours of each other and used the same payload infrastructure, indicating a single coordinated operator.
Timeline
- 2021-11-04 ~14:00 UTC —
coa@2.0.3,2.0.4, and2.1.xmalicious versions begin landing. - 2021-11-04 ~16:00 UTC — Public discovery via failing CI builds across the React ecosystem (the legitimate
coahad been at2.0.2for years; new patches broke installs). - 2021-11-04 ~17:00 UTC —
rc@1.2.9,1.3.9, and2.3.9malicious versions discovered with similar characteristics. - 2021-11-04 ~19:00 UTC — npm removes all malicious versions; clean replacements re-published.
- 2021-11-04 ~22:00 UTC — GitHub Security Advisories published for both packages.
Attack Vector
Both packages were essentially unmaintained at the time of takeover. The legitimate coa had not received a release in three years; rc had been stable for similar duration. Both compromises followed the same pattern as ua-parser-js:
- Maintainer npm account credentials compromised via credential reuse / credential stuffing.
- Attacker published version bumps that looked like routine maintenance releases (
2.0.3→2.0.4, etc.) rather than dramatic version jumps. preinstallscript in each malicious version downloaded a platform-specific payload.- Linux install: cryptominer + minimal credential collection.
- Windows install: cryptominer + DanaBot-family credential stealer (same payload family observed in
ua-parser-js).
The coordination signal — both packages hijacked the same day, both using the same payload infrastructure — strongly suggests a single operator working through a list of dormant-but-popular npm accounts harvested from a credential breach corpus.
Tokens & Credentials Exposed
Identical scope to ua-parser-js because the payload was the same family:
- Browser-stored credentials (Chrome, Edge, Firefox password and cookie stores).
- OS-level credentials (Windows Credential Manager, FTP client stored credentials).
- Cryptocurrency wallet files (
wallet.dat, MetaMask local storage, hardware-wallet companion data). - Session tokens for any post-2FA session active in the affected browser.
For the rc install footprint specifically, the practical exposure was enormous: rc is a transitive dependency of huge swaths of the Node.js tooling ecosystem (everything from npm itself in some configurations, to test runners, to CLI tools). Any developer workstation or CI runner that ran npm install during the exposure window potentially pulled the malicious version.
Confirmed Impact
- Both packages quickly removed by npm; window was ~2–5 hours each.
- GitHub Security Advisories issued classifying installs of affected versions as fully compromised.
- DanaBot operator continuity confirmed: malware analysts tied the C2 infrastructure to the same operation as
ua-parser-js, suggesting a deliberate campaign rather than independent incidents. - No specific organization disclosures, but Fortune-500 IR activations were widely reported in industry discussion channels.
Mitigation & Lessons
The Mitigation playbook is identical to ua-parser-js:
- Treat any host that pulled a malicious version as fully compromised; reformat workstations and rebuild CI runners.
- Rotate every credential reachable from the affected host — browser-stored, OS-stored, cloud, source control, third-party SaaS.
- Audit for DanaBot-family persistence (scheduled tasks, registry run keys).
The structural lessons that this pair of incidents added to the field:
- Coordinated takeovers are a deliberate operating model. A single attacker with a credential corpus can hit multiple dormant-but-popular packages within hours. The defender response cost scales with the number of packages compromised, not with the technical complexity of each compromise.
- "Unmaintained" is a security state, not a maintenance state. A package that has not received a release in three years is not safe by virtue of stability — it is dangerous because the security posture of its publishing credentials has not been reviewed in three years.
- Detection by ecosystem-wide CI failure is the wrong end of the funnel. Both
coaandrcwere detected because their version bumps broke downstream installs, not because npm or any monitoring vendor flagged the publish event itself.
Cremit Analysis
This pair is the cleanest ghost-key + drifted-key combination in the index.
Ghost Key: both maintainer credentials were long-lived static identities held by individuals whose engagement with the package had ended years earlier. There was no operational signal — no team, no review, no rotation calendar — to detect that the credential was now in someone else's hands.
Drifted Key: both packages had drifted from small utilities to load-bearing transitive dependencies in the JavaScript ecosystem. rc in particular ended up underneath a substantial fraction of all Node.js tooling. The trust model that worked for a small utility was inadequate for the blast radius the package had accumulated.
The NHI Severity Index score of 8.7 reflects ecosystem-wide reach (especially rc at ~14M weekly downloads), production reachability (the credentials harvested were live OS and browser credentials), and variable privilege levels.
What this pair adds beyond ua-parser-js is the demonstration that the technique scales. Once an attacker has the playbook — credential corpus, dormant-package list, copy-paste DanaBot payload — additional takeovers cost the attacker close to nothing. The defender side has no equivalent leverage. Each incident requires individual investigation, individual customer contact, individual credential rotation. The asymmetry is structural and is exactly what credential-leak detection platforms like Argus are built to flatten by surfacing exfiltrated credentials in the public ecosystem before downstream re-use.
참고 자료
- [1]GitHub Security Advisory GHSA-3jfq-g458-7qm9 (coa)primary·2021-11-04·github.com
- [2]GitHub Security Advisory GHSA-g2q5-5433-rhrf (rc)primary·2021-11-04·github.com
- [3]Popular 'coa' NPM library hijacked to steal user passwordsreporting·2021-11-04·bleepingcomputer.com
- [4]Hackers update 'rc' npm library with malware mimicking the ua-parser-js attackreporting·2021-11-04·bleepingcomputer.com
