Editorial

Chai npm brandjacking campaign: 25 packages, 11 weeks

RobertUpdated Jun 30, 20269 min read
Tree diagram showing the Chai npm package with multiple malicious brandjacked variants branching off it, detected over a three-week period.

Twenty-five packages, one library, eleven weeks of history: a brandjacking campaign against Chai#

Most of what gets published about supply chain attacks is reactive. An attack happens, it gets disclosed, researchers analyse it after the fact. This post is different. It's something we noticed by checking the live Attestd API against package names following a suspicious pattern: a sustained brandjacking campaign against the Chai assertion library with a compromise history stretching back to April and at least twenty-five malicious packages identified, most of it never connected end to end until now.

Attestd's detection ledger itself is three weeks old, and most of these compromises fall within that window. One package, chai-as-init, has a compromise timestamp that predates the ledger by two months, surfaced now because the live API still flags it and its history fits the same pattern. This is the first piece of original analysis we're publishing from Attestd's data rather than a writeup of an already-disclosed incident.


What is brandjacking#

Sonatype's research team has documented a shift in how attackers name malicious npm packages. The old model was typosquatting: publish expres hoping a developer mistypes express. The newer model, which Sonatype calls brandjacking, is more deliberate. Attackers publish packages with names that sound like they belong next to a trusted library, using suffix-addition, version mimicry, and naming patterns that blend into the surrounding ecosystem rather than imitating a single misspelling.

Sonatype's reporting on a Lazarus Group campaign earlier this year named Chai specifically, alongside Buffer and React, as a library being targeted with this technique.

Our ledger shows that campaign, or one using an identical technique against the same library, did not stop. It has continued mutating through at least eleven distinct package names over the past three weeks.


The chai-as-promised cluster#

chai-as-promised is a widely used Chai plugin for testing promise-based code. It is exactly the kind of trusted, narrowly-named utility that brandjacking is built to imitate. A developer scanning a package list for something that handles promise assertions sees a name like chai-as-attested or chai-as-assured and has no obvious reason to suspect it.

The following packages, all following the chai-as-[suffix] naming convention, return supply_chain.compromised: true against the live Attestd API. Dates below are compromised_at, the actual compromise timestamp sourced from OSV, not the date our pipeline happened to detect them:

PackageCompromised
chai-as-initApril 16
chai-as-victimedJune 11
chai-as-decryptedJune 16
chai-as-polishedJune 16
chai-as-tokenizedJune 16
chai-as-attestedJune 19
chai-as-forgetedJune 19
chai-as-upheldedJune 19
chai-as-operatedJune 23
chai-as-builtJune 25
chai-as-assuredJune 26

chai-as-init is the outlier and the most important data point in the set. Its compromised_at timestamp, sourced from OSV, is April 16, 2026, three weeks after MoltX's March 26 writeup on chai-as-chain documented this exact technique against this exact library. That compromise predates Attestd's own detection ledger, which has only been running for three weeks. We did not catch chai-as-init in real time; we are surfacing it now because the live API still flags the version as compromised and the historical timestamp is part of the same campaign pattern. The remaining ten packages cluster tightly between June 11 and June 26, within the ledger's operating window, suggesting either a pause and relaunch after April or a slower early phase followed by a sharp escalation in volume.

chai-as-init also has a public advisory: indece.com flagged it independently. The other ten packages in this cluster have no advisory URL attached in OSV, meaning Attestd's detection is currently the only structured signal available for them.

Eleven packages, eleven different suffixes, the same prefix, the same library being impersonated, spanning over two months. New variants appeared every few days during the June phase, consistent with an attacker publishing fresh packages as previous ones were caught and removed rather than relying on a single long-lived package to do the work.

We have independent confirmation that this technique against this specific library is not new. MoltX, a security research group focused on AI agent infrastructure, documented chai-as-chain on March 26, 2026, a separate package using the same naming logic and also impersonating chai-as-promised. Their analysis specifically flagged the risk to AI agent deployments, noting that frameworks like LangChain pull in hundreds of transitive dependencies, making manual review of each one impractical.

Three months later, the same technique against the same library is still active, with a substantially larger and more rapidly mutating set of package names than the single instance documented in March.


A second, parallel cluster#

Alongside the chai-as- cluster, our ledger shows a second, structurally distinct group of malicious packages targeting the broader Chai testing ecosystem rather than chai-as-promised specifically:

PackageCompromised
chai-mocksJune 8
chai-check-errorJune 10
chai-net-testJune 11
chai-decJune 11
chai-web3-testkitJune 12
chai-utils-testJune 13
chai-guidJune 16
chai-pluginJune 16
chai-plugin-kitJune 16
chai-solidity-testkitJune 16
chai-plugin-helperJune 16
chai-test-mocksJune 16
chain-chai-testJune 16
chai-assert-kitJune 19

This cluster is notable for two reasons. First, the volume on June 16, seven packages compromised within roughly an hour of each other based on the timestamps in our data, suggests a batch publish rather than organic individual releases. Second, the inclusion of chai-solidity-testkit and chai-web3-testkit, the latter compromised June 12, four days before the main batch, points toward a target profile that overlaps with smart contract and blockchain developers specifically, a population that shows up repeatedly across 2026's supply chain campaigns given the direct path from compromised developer credentials to cryptocurrency theft.

We cannot determine from available data whether this cluster and the chai-as- cluster are operated by the same actor. The naming conventions are different enough to suggest they may be separate campaigns independently targeting the same library, or a single operation running two naming strategies in parallel. What we can say is that both clusters target Chai specifically, both appeared in the same three-week window, and both follow the brandjacking pattern Sonatype has documented in connection with Lazarus Group activity.


What the API returns#

bash
curl "https://api.attestd.io/v1/check?product=chai-as-init&version=1.4.7" \
  -H "Authorization: Bearer $ATTESTD_API_KEY"
json
{
  "product": "chai-as-init",
  "version": "1.4.7",
  "supported": true,
  "risk_state": "none",
  "risk_factors": [],
  "actively_exploited": false,
  "remote_exploitable": false,
  "authentication_required": false,
  "patch_available": false,
  "fixed_version": null,
  "confidence": 0.95,
  "cve_ids": [],
  "cves": null,
  "last_updated": "2026-06-30T01:09:04.298439Z",
  "supply_chain": {
    "compromised": true,
    "sources": ["osv"],
    "malware_type": "malware",
    "description": "Malicious code in chai-as-init (npm)",
    "advisory_url": "https://www.indece.com/en-US/blog/7df041ba-feb1-4d87-918b-7fc2c709d805",
    "compromised_at": "2026-04-16T20:36:13Z",
    "removed_at": null
  },
  "typosquat": null
}
bash
curl "https://api.attestd.io/v1/check?product=chai-web3-testkit&version=1.0.1" \
  -H "Authorization: Bearer $ATTESTD_API_KEY"
json
{
  "product": "chai-web3-testkit",
  "version": "1.0.1",
  "supported": true,
  "risk_state": "none",
  "risk_factors": [],
  "actively_exploited": false,
  "remote_exploitable": false,
  "authentication_required": false,
  "patch_available": false,
  "fixed_version": null,
  "confidence": 0.95,
  "cve_ids": [],
  "cves": null,
  "last_updated": "2026-06-30T01:09:04.298439Z",
  "supply_chain": {
    "compromised": true,
    "sources": ["osv"],
    "malware_type": "malware",
    "description": "Malicious code in chai-web3-testkit (npm)",
    "advisory_url": null,
    "compromised_at": "2026-06-12T16:11:50Z",
    "removed_at": null
  },
  "typosquat": null
}

risk_state: none on every package in both tables. No CVE IDs. Every standard vulnerability scan passes all twenty-five clean. supply_chain.compromised: true is the only signal that exists for any of them, and for twenty-four of the twenty-five, Attestd's detection is the only structured record at all, since no OSV advisory URL is attached.

Why Chai specifically#

Chai is a near-ubiquitous assertion library in the JavaScript testing ecosystem. It is a dependency a developer adds without much scrutiny, because it is a development-time tool rather than production code, and because the surrounding plugin ecosystem, chai-as-promised among the most common, is exactly the kind of small, single-purpose package that gets installed on trust.

That makes it a structurally good target. A compromised testing dependency executes in CI/CD pipelines and on developer machines with the same access as any other installed package, but it carries less scrutiny than a production dependency because nobody expects a test helper to be dangerous.

The March research connecting this to AI agent pipelines specifically is worth restating. A LangChain-based agent project can easily carry a dependency tree deep enough that a brandjacked test utility several layers down goes unnoticed in a routine dependency review. The attack surface is not the agent code. It is the testing and tooling layer underneath it.


What this means#

This is not a single incident with a clean before-and-after. The earliest known instance, chai-as-init, traces back to April 16, 2026, based on its OSV-sourced compromise timestamp, predating Attestd's own ledger. But the pattern has continued well within our three-week detection window, with ten more variants compromised between June 11 and June 26 alone. New package names keep appearing. Old ones get caught and removed. The underlying technique, brandjacking a trusted assertion library plugin, does not change.

This is the kind of pattern that a one-time scan cannot catch, because there is no single moment to scan against. It requires continuous monitoring across weeks, which is what Attestd's supply chain pipeline does by design. Every package in both tables above returns supply_chain.compromised: true today.

Attestd's detection ledger has been live for three weeks. We will continue watching this campaign going forward and will publish a follow-up if it continues to evolve.


Coverage#

All packages listed above are covered by Attestd and return supply_chain.compromised: true, sourced from OSV. Detection timestamps and commit hashes for each are recorded in the public detection ledger.

Ledger: github.com/attestd-io/detection-ledger Live dashboard: attestd.io/docs/detection-ledger API documentation: attestd.io/docs