
Dependency cooldowns filter some fast-moving attacks, but they still depend on someone else detecting the compromise first. See why controlling behavior at runtime closes the gap.
September 8, 2026
8 Min Reads
Endura Security

It is one of the most reasonable-sounding controls in software supply chain security, and we hear it constantly: "We delay adopting new dependencies for a few days so the community has time to detect and pull anything malicious before it reaches us."
It is a good instinct. The data even supports it. Most malicious package versions are loud and short-lived. They get caught, reported, and yanked within hours, and a waiting period filters out the entire category of smash-and-grab attacks that depend on getting installed before anyone notices. If you are not doing this yet, you should be. The package ecosystems agree: pnpm now ships a release-age setting on by default, and the practice has matured into first-class support across npm, pnpm, Yarn, and Bun.
So this is not an article arguing that cooldowns are useless. They are useful. This is an article about what a cooldown actually is as a control, what it quietly assumes, and why the attacks that turn into a credential-rotation fire drill are precisely the ones it cannot see.
Strip away the mechanism and a cooldown is an outsourced-detection control. It does not inspect the dependency. It does not constrain the dependency. It places a bet: that somewhere out there, another organization gets compromised first, notices, raises the alarm, and gets the malicious version pulled, all inside your waiting window, and all in a way you will hear about and act on.
When that bet pays off, it pays off cheaply, and that is why the control is popular. But the bet rests on a stack of assumptions, and every one of them has been broken by a real, named incident in the last eighteen months. Let's walk through each of them.
A cooldown ages the artifact on the registry. It assumes the danger lives in that artifact, so that letting the artifact sit also lets the danger age and get discovered.
The PhantomRaven campaign breaks that assumption at the root. The packages declared no dependencies and contained almost nothing. The real payload was pulled at install time from an attacker-controlled URL using a technique researchers call Remote Dynamic Dependencies. Because the registry never hosted the malicious code, registry-based scanners never inspected it, and the package on npm looked clean for as long as anyone cared to wait. A cooldown can age the harmless shell on the registry forever; the dangerous part was never there to age. Worse, because the payload is fetched fresh on every install, the attacker can serve benign code to researchers and the real thing to a corporate build, or stay quiet for weeks to pass inspection, then flip the switch. The campaign reached more than 80,000 downloads across over 200 packages before discovery.
A cooldown models adoption as a deliberate event: a new version appears, you wait, then you take it. It assumes nothing changes about a dependency you have already taken.
The tj-actions/changed-files compromise (CVE-2025-30066) removes that assumption. Rather than publishing a new release, the attacker retroactively rewrote the existing version tags so that references you adopted months earlier now pointed at a single malicious commit. The injected code dumped CI runner memory and leaked secrets into workflow logs across more than 23,000 repositories. There was no new version to cool down on. The thing you had already trusted changed underneath you. (Pinning to immutable commit SHAs helps here, but a time-based cooldown does nothing, because no clock was started.)
A cooldown is a recency filter. It assumes that "new" correlates with "risky," so holding the new thing at arm's length reduces exposure.
The XZ Utils backdoor (CVE-2024-3094) is the clean refutation. An actor using the name "Jia Tan" spent roughly three years making legitimate contributions to a critical compression library, earned co-maintainer trust, and only then shipped a backdoor in versions 5.6.0 and 5.6.1. A five-day cooldown is meaningless against code planted by a trusted maintainer that then ages normally inside shipped releases, and so is a thirty-day or six-month one. Note also how it was caught: not by community flagging inside any window, but by an engineer who noticed half-second SSH login delays and went looking. The backdoor did not announce itself in metadata or a version number. It announced itself in what the software did when it ran. No amount of waiting surfaces that. Only watching execution does.
A cooldown assumes the community has something to flag, that a poisoned release carries some visible tell that prompts the report that gets it pulled.
Two incidents from May 2026 remove that assumption. In the TanStack compromise, malicious packages were published by the project's own legitimate release pipeline using its trusted identity, and could therefore carry valid SLSA provenance attestations: the build system really did build and publish them. In the durabletask incident on PyPI, three malicious versions were published using a compromised API token rather than the project's normal workflow. In both cases there is no anomaly at publish time for anyone to surface. The cooldown runs its clock against a release that looks entirely legitimate, and at the end of the window it is exactly as legitimate-looking as it was at the start.
A cooldown assumes the detect-and-pull cycle is faster than the spread, that the window is long enough for the alarm to reach you before the damage does.
The Shai-Hulud worm inverts that race. The second wave, in November 2025, self-propagated by stealing npm tokens and automatically republishing malicious versions of every package a compromised maintainer controlled. Within hours of detection it had compromised over 700 packages, created more than 27,000 malicious repositories, and exposed roughly 14,000 secrets across 487 organizations, eventually backdooring nearly 800 unique packages. Two properties matter for the cooldown argument. First, the spread is automated and ecosystem-wide, so "the community will catch it in a few days" is racing a worm that moves in hours. Second, the worm establishes persistence and re-publishes through legitimate accounts, so "the bad version was pulled" does not mean the incident is over.
Finally, a cooldown assumes the attack arrives through the package manager it governs. Plenty don't.
GlassWorm spread through VS Code extensions on the OpenVSX marketplace, a channel no npm or pnpm release-age setting touches, and one where extensions auto-update by default, so victims received malicious versions with no action at all. It hid its code in invisible Unicode characters that do not render in an editor, harvested npm, GitHub, and Git credentials, and used them to compromise further extensions and packages. It also pointed its command-and-control at memos embedded in a public blockchain, so even after takedowns the operators could redirect every infected machine with a new transaction. "The community will pull it" assumes there is a single thing to pull. Here there was not. This is the same lesson as the poisoned IDE extension in The Build Is the Breach: if it runs where your code is written and your credentials live, it is part of your supply chain whether or not it appears in a manifest.
A common rejoinder is that a properly configured cooldown applies to the whole tree, transitive dependencies included. That is mechanically true in tools like pnpm. But it misses where the real weakness is.
The cooldown's value was never the age check itself, it was outsourced detection. And detection is a function of scrutiny, not calendar time. A popular direct dependency gets enormous scrutiny. A package buried four layers deep in your tree gets almost none, you did not choose it, you are not watching its releases, and you would not recognize the advisory if one appeared. Yet that deep, unwatched layer is most of your attack surface, and it is exactly where the self-propagating worms land, because they don't compromise the packages you evaluated. They compromise a maintainer and ride in as a transitive dependency you never looked at. So the cooldown is strongest precisely where you face the least risk, and weakest precisely where the modern campaigns operate.
Every section above is about an attack the cooldown lets through. But the control is not free even when it works, and the cost points in the opposite direction: a cooldown delays the patches you actually want.
A waiting period cannot tell a malicious version apart from an urgent fix. When a maintainer ships a patch for a disclosed vulnerability, your cooldown holds it back for the same number of days it holds everything else, and for that entire window you keep running the version with the known, published flaw. The authors of cooldowns.dev name this drawback themselves: an aggressive cooldown can delay legitimate security patches, which is why they advise pairing it with active vulnerability alerting so critical fixes still reach you quickly.
That puts the control in a vise. Shorten the window and you catch fewer of the slow-burn attacks from the sections above. Lengthen it and you sit longer on code with a weaponizable, already-public flaw. There is no setting that escapes both pressures, because a single blunt delay is being asked to balance two risks that pull in opposite directions.
The usual answer is that update bots like Renovate and Dependabot exempt security updates from the cooldown, and you should turn that on. But look at what the exemption depends on: a fix has to be recognized and labeled as a security update, in an advisory feed, in time for the bot to act on it. Silent fixes, patches that land before a CVE is assigned, and ecosystems without that exemption all fall back into the delay. The escape hatch runs on the same fuel as the rest of the cooldown, someone else noticing first.
Line the six assumptions up and a pattern appears. A cooldown protects you only when the malice is in the artifact, the adoption is a discrete event, the malice is recent, the malice is visible, detection beats propagation, and the attack comes through the gated channel. PhantomRaven breaks the first. tj-actions breaks the second. XZ breaks the third. TanStack and durabletask break the fourth. Shai-Hulud breaks the fifth. GlassWorm breaks the sixth.
None of these is a reason to drop the cooldown. It still filters out the fast, noisy attacks that depend on getting installed before anyone notices, and that is real value for a configuration change. The point is narrower and more important: a cooldown is the wrong control to be your last line, because its entire premise is that someone else notices first. Anything that defeats "someone else notices first" walks straight through it, and turning the window up to compensate only strands you longer on the vulnerabilities you already know about.
The control that does not depend on anyone else noticing is one that governs what a component is allowed to do when it executes. That question has the same answer whether the package is new or old, attested or not, direct or transitive, flagged by the community or not yet on anyone's radar.
Endura's eBPF-based platform sits below the package manager, below the action, below the extension, and below the install script, at the kernel level, where intent does not matter and behavior does. The policy does not care how long a dependency has been published. It cares what the dependency tries to do.
npm install, a process may reach the package registry and nothing else: not an attacker-controlled URL fetched by a remote dynamic dependency, and not a blockchain-hosted C2 endpoint.~/.aws/credentials, ~/.npmrc, ~/.ssh/, or password-manager artifacts.
When a component crosses one of those lines, the kernel enforces the decision before the secret leaves, regardless of whether that component is a five-day-old npm package, a years-old maintainer backdoor, a retroactively rewritten GitHub Action, or a worm wearing a maintainer's stolen credentials. This is the control that holds when every assumption behind a cooldown fails. And because the protection never came from waiting, it dissolves the vise: you can take a security patch the moment it ships instead of choosing between patching fast and staying out of the blast radius. Keep the cooldown to thin out the noise if you want, but the decisive boundary, the one that actually stops a credential from leaving your build, is enforced here, at runtime, on your own terms, and it does not wait on anyone else to notice first.
So keep the waiting period. Just don't mistake it for a defense. The boundary that actually holds is the one you enforce yourself, not the one you hope a stranger trips first.
Learn how Endura Security's eBPF-based platform provides runtime enforcement across your CI/CD pipelines and production workloads. Request a demo to see how kernel-level policy enforcement blocks credential theft, unauthorized network connections, and anomalous process execution that a dependency cooldown cannot, no matter how long you wait.



