Inspiration

Every developer has run npm install and accepted, without a second thought, that the bytes arriving on their machine are the bytes the maintainer actually published. We started pulling on that thread and did not like what we found.

More than 454,600 new malicious packages were catalogued across the major open-source registries during 2025 — a 75% jump year on year — and over 99% of them landed on npm. Supply-chain compromise is now the second most common initial attack vector in enterprise breaches, implicated in 15% of them, at an average cost of USD 4.91 million and a mean lifecycle of 267 days. And the attacks are moving to the account layer: 92% of every npm account-takeover advisory ever recorded was filed in 2025 alone.

What struck us was not the scale. It was that every defence we could find ultimately asks you to trust the registry operator — the same party that can unpublish a version, re-point a tag, or be taken over. There is no independently verifiable record of what a package version actually was at the moment it was published.

The web solved a structurally identical problem in 2013. Certificate authorities could mis-issue certificates and nobody could prove it afterwards. The answer was not a more trustworthy CA — it was Certificate Transparency, a public append-only log that made mis-issuance detectable by anyone. Package registries sit exactly where CAs sat. So we are building the equivalent for package artifacts.

What it does

CAIRN lets any team prove a dependency is byte-for-byte what its maintainer published, before it ever reaches a build.

  1. Maintainers attest. On release, a CLI computes a reproducible SHA-256 Merkle digest of the artifact, signs it with an EIP-712 typed signature, and writes it to an append-only smart contract.
  2. Independent attesters corroborate. A set of nodes — run by parties with no relationship to the maintainer or the registry — re-fetch the artifact from the public registry, recompute the digest, and co-sign on-chain only if it matches. A mismatch is recorded as a divergence, not discarded.
  3. Quorum decides. An attestation counts as valid only once M of N attesters agree. Trust is distributed across the attester set instead of concentrated in any operator.
  4. CI enforces. cairn verify resolves your lockfile, digests every artifact it is about to install, checks on-chain quorum state, and fails the build with a non-zero exit code on anything unattested, under-quorum, or divergent.

The key property: CAIRN never tries to decide whether code is malicious. It detects divergence — the same version string resolving to different bytes than were attested. That is the mechanical signature of republication, tag re-pointing and account takeover, and it is visible from the very first victim rather than after a disclosure. Signature-based scanners cannot say the same; one research corpus of 106 supply-chain campaigns recorded zero CVEs assigned across all of them while they were being actively exploited.

How we're building it

  • On-chain: Solidity 0.8.26 with Hardhat and OpenZeppelin. AttestationRegistry.sol stores package identity, version, artifact digest and IPFS payload CID, verifies EIP-712 signatures, and deliberately exposes no update and no delete path — immutability is a property of the data structure, not a promise in a terms-of-service document. QuorumPolicy.sol holds the attester set and the M-of-N threshold.
  • Off-chain: Node.js attester nodes with a registry-fetch and canonicalisation adapter; an Express indexer using a viem event watcher into MongoDB; a divergence monitor polling the public registry for byte-level changes to already-attested versions.
  • Client: A TypeScript CLI (publish + verify) and a Next.js 16 dashboard with wagmi for chain reads, showing each package's full attestation timeline and quorum state.
  • Deployment: Contracts on a public EVM testnet, dashboard and API on a live public URL, three attester instances with distinct keys on separate hosts — so the quorum being demonstrated is real, not simulated.

Challenges we're anticipating

Canonicalisation is the hard part. Two honest parties must derive an identical digest from the same release, which means the digest has to be computed over a normalised file tree rather than the raw archive — archive metadata, timestamps and compression settings all differ harmlessly between fetches. Getting this wrong produces false divergence alerts, which would destroy trust in the tool faster than any missed attack.

Keeping the on-chain footprint honest. Storing full attestation payloads on-chain would be wasteful, so only the digest and an IPFS CID are anchored. That split has to be designed so the on-chain record remains independently meaningful even if off-chain storage becomes unavailable.

Resisting scope creep. Staking and slashing for attesters, zero-knowledge proofs of build reproducibility, and multi-registry support are all natural extensions — and all of them are explicitly out of scope. The core guarantee has to work end-to-end first.

What's next

Extending beyond npm is an adapter-sized change rather than a redesign, which matters because multi-ecosystem campaigns targeting npm and PyPI simultaneously are already documented. Beyond that: an economic layer so attesters are staked and slashable, and reproducible-build proofs so an attester can verify not just that an artifact is unchanged, but that it genuinely came from its stated source.

Open-source software is shared public infrastructure, and its security currently rests on the unpaid vigilance of maintainers and the goodwill of registry operators. A verification layer that no single party owns shifts that burden from trust to mathematics — for every downstream developer at once.

Built With

Share this project:

Updates

Submission history