After every npm supply chain incident, the advice tends to converge on two controls: require provenance so you know what source and build process produced an artifact, and use --ignore-scirpts so package lifecycle hooks cannot execute during installation. Both are useful controls. The ChainDrop and MemTensor compromises in August and September 2026 show why neither answers the broader question of whether a newly published release is actually consistent with the software it claims to be.
ChainDrop: the attestation was real
On August 4, 2026, an attacker took over the GitHub account of the maintainer behind packages including keyv, cacheable, flat-cacheable, and flat-entry-cacheable. The attacker pushed poisoned commits into the repositories and allowed the projects' existing release workflows to do the rest.
That distinction matters because the resulting artifact had valid provenance. keyv@6.0.0 was published at 09:35 UTC through npm's OIDC trusted publishing mechanism with a valid SLSA provenance attestation. The attestation faithfully recorded the commit that the release pipeline built. Nothing was wrong with the provenance itself. The problem was that the commit being built had already been compromised.
Provenance establishes the relationship between an artifact, its source commit, and the build process. It does not establish that the source commit was authorized or that the code in that commit still represents the maintainer's intended software. In ChainDrop, the attacker controlled the source repository first, so the legitimate build system became part of the delivery mechanism for the malicious release.
The payload itself was introduced through a preinstall hook. node setup.mjs downloaded the genuine Bun runtime from GitHub and used it to execute an obfuscated second stage. StepSecurity measured that stage at 727,680 bytes and found functionality for harvesting npm, GitHub, and cloud credentials, including secrets available from GitHub Actions runner memory. Those credentials were then used to propagate the worm into additional packages. By 18:10 UTC, StepSecurity had counted 444 packages and 2,212 versions in the campaign.
Here, --ignore-scripts does address the primary infection path. If the lifecycle hook does not execute, the dropper does not run during installation. But ChainDrop also planted .cluade.claude and .vscode hooks into repositories it could reach. Those mechanisms can execute when a developer opens a project and do not depend on npm instal. That is an important distinction: blocking installation-time execution can remove one execution path without proving that the package or repository is clean.
MemTensor: nothing ran at install
The September 23 MemTensor compromise followed a different path. Malicious releases of the OpenClaw plugin @memtensor/memos-cloud-openclaw-plugin appeared at versions 0.1.21, 0.1.23, and 0.1.25, while the MemoryOSPython package was compromised at version 2.0.34. The packages carried the same Go implant, sckit.
In this case, the attack entered through the release process rather than an installation hook. Attacker-controlled commits on short-lived branches modified a validation script that ran early in the GitHub Actions workflow. The modified script used $GITHUB_ENV to set the BASH_ENV environment variable. Bash then sourced the referenced file before subsequent shell commands, allowing the attacker's code to run ahead of the legitimate publishing step, capture the npm or PyPI token, and deliberately fail the step.
That mechanism matters because the malicious package itself did not need an install script. The captured publishing credentials allowed the attacker to get the implant into the packages through the release process, after which the malware executed during normal package use.
For the OpenClaw plugin, sckit starts when the gateway starts and again during memory recall. For MemoryOS, it starts when the library configures logging, something that occurs on common import paths. There is therefore nothing for --ignore-scripts to prevent. The code is already part of the package and executes when the application loads or uses it.
Provenance presented a different problem here. Neither affected package had previously carried an attestation, so there was no established provenance baseline that could distinguish the malicious release from the package's normal publishing history.
The common signal was in the release itself
The two attacks used different entry points and different execution mechanisms, but both left evidence in the artifacts and their surrounding release history.
In ChainDrop, keyv@6.0.0 differed from the 6.0.0-rc.1release published the previous day in exactly three places: two newly introduced obfuscated files and a new preinstalldeclaration. The compiled dist/ files were otherwise byte-identical. A package that had not previously executed code during installation had suddenly acquired a mechanism for downloading a runtime and launching a second-stage payload.
The MemTensor packages showed a different kind of discontinuity. The MemoryOS wheel grew from roughly 951 KB in version 2.0.33 to about 19 MB in 2.0.34 because it now contained six platform-specific binaries. The npm plugin published five versions in two hours and fourteen minutes, alternating between clean and malicious contents. The first malicious tarballs also had no corresponding commit in the repository, a discrepancy that helped a researcher identify the compromise and open issue #173. SafeDep's later analysis similarly documents the rapid alternation between clean and malicious package contents.
These are not vulnerability signatures in the traditional sense. There may be no CVE associated with a newly compromised release, and a reputation-based system has little to work with when the first malicious version is published. They are changes in the software's own history: a new capability, a new binary, an unexpected execution path, an artifact that does not correspond to repository history, or a publishing pattern that is unlike what the project normally produces.
That suggests a broader set of questions for package security. Did the release introduce an execution mechanism that did not exist before? Did its contents or capabilities change materially? Does the published artifact correspond to source that actually exists in the repository? Does the release sequence make sense for this project?
Provenance answers one of those questions. An SBOM answers another by describing what is present in the artifact. Vulnerability scanning looks for known weaknesses in those components. Installation controls restrict one class of execution. None of these controls, by themselves, asks whether the new release still looks and behaves like the package's own established history.
Looking beyond provenance and known vulnerabilities
This is where behavioral and package-history analysis becomes useful. Instead of evaluating a release only against external indicators such as known CVEs, signatures, or provenance requirements, the package can also be evaluated against itself.
That means looking at changes in files and capabilities across releases, newly introduced binaries or execution paths, the relationship between published artifacts and source commits, and publishing behavior over time. The objective is not to replace provenance, SBOMs, vulnerability scanning, or installation controls. It is to examine a different part of the trust problem: whether a release has acquired characteristics that are inconsistent with the software that came before it.
This distinction becomes increasingly important as software supply chains expand beyond conventional libraries. AI coding assistants, agent frameworks, plugins, model tooling, and developer automation introduce more packages into environments where code may execute as part of an IDE, an agent session, an application startup, or a runtime operation rather than during installation. CleanStart has previously examined this broader expansion of the software supply chain in its analysis of the Hugging Face incident and in its discussion of how AI software supply chains are repeating established open source security patterns.
Where Clean Libraries fits
That is the problem Clean Libraries is designed to address. It evaluates library releases against the package's own history and looks for changes that may indicate an unexpected or suspicious release, including behavioral changes, capability changes, artifact-source inconsistencies, and unusual publishing patterns.
The goal is complementary verification. Provenance can tell you that an artifact was produced from a particular commit through a particular build process. Clean Libraries can ask whether that release is consistent with the package's established behavior and history. An SBOM can tell you what components are present. Behavioral analysis can identify when the package itself has changed in ways that deserve investigation.
For ChainDrop, the important lesson is not that provenance was ineffective. The provenance was accurate. It faithfully described a build from compromised source. For MemTensor, the lesson is not that --ignore-scriptsis ineffective. It blocks installation-time lifecycle execution, but there was no installation hook to block. The larger lesson is that software supply chain controls operate at different boundaries, and attackers can move to another boundary when one is protected.
The retrospective analysis of these incidents shows the kinds of signals that a system such as Clean Libraries is intended to surface. It is not a claim that Clean Libraries detected either compromise at the time.
As software becomes more dynamic and dependencies enter applications through more paths, verifying how a package was built is only part of establishing confidence in what was actually delivered. The release itself also needs to make sense: its contents, capabilities, execution behavior, relationship to source, and publishing history should remain consistent with the software that developers thought they were consuming.



