A malicious package does not need to stay online for a week. It only needs to be available when your developer laptop, CI runner, dependency bot, or editor auto-update mechanism asks for it.
That is the uncomfortable lesson from the latest wave of developer supply chain incidents. Fast takedown is useful. It is not the same as prevention.
TL;DR
- Supply chain malware often wins in the first minutes or hours after publication.
- A minimum package age policy delays adoption of new dependency versions until the ecosystem has had time to detect obvious abuse.
- This is not a replacement for pinning, provenance, OIDC, staged publishing, or code review. It is a timing control that makes those controls more likely to matter.
- Apply shorter delays to security fixes and emergency releases, longer delays to routine updates, editor extensions, development-only packages, and AI tooling.
- If your organization cannot answer “what installs new code automatically within the first hour?”, it does not yet have this control.
The Attack Window Is Small
Modern supply chain attacks exploit automation. A package is published, a lockfile update lands, a CI job runs, an extension auto-updates, or a developer opens a trusted workspace. The malicious code executes before a human has read a changelog.
That is why “the malicious version was removed quickly” can be a misleading comfort. If the attacker gets 18 minutes, three hours, or one business morning, that may be enough for token theft, repository cloning, CI/CD persistence, or package republishing.
The defensive question is not only:
How fast can we detect and remove a bad release?It is also:
Why were we willing to install a brand-new release before anyone else had time to detect it?What Minimum Package Age Means
Minimum package age is a policy that says:
Do not install or propose a newly published dependency version until it is at least X old.The value of X depends on the context. Three hours may reduce exposure to obvious registry abuse. Twenty-four to seventy-two hours may be more appropriate for routine dependency automation. High-risk developer tools, editor extensions, build plugins, and packages with install scripts may deserve a longer window.
This is not “never update.” It is “do not be first unless there is a reason.”
The control works because many malicious releases are discovered quickly by maintainers, registries, downstream users, and security vendors. A delay gives the ecosystem time to raise the flag before your systems execute the new code.
Where It Helps
Minimum age is most useful when new code is installed automatically or semi-automatically:
| Surface | Risk | Useful delay |
|---|---|---|
| Dependency bots | Opens PRs (pull requests) for malicious versions before review context exists | Cooldown before PR creation or automerge |
| CI/CD builds | Pulls new transitive packages during build | Lockfiles, mirrors, and delayed registry promotion |
| Developer laptops | Installs packages or extensions with local credential access | Approved catalogs and extension age rules |
| Editor extensions | Auto-update moves malicious code into trusted workspaces | Disable uncontrolled auto-update for high-risk extensions |
| AI coding tools | Pull plugins, skills, templates, and packages with little review | Treat agent tooling as executable dependency surface |
The target is not only production runtime dependencies. Development dependencies often run with better access than production code: source trees, SSH keys, package tokens, cloud profiles, and local credentials.
Where It Does Not Help
This control has limits.
It will not stop a maintainer who has been compromised for weeks. It will not detect a malicious change hidden inside a legitimate release. It will not protect you if your lockfile already points to a bad version. It also creates a tradeoff: delaying ordinary updates can delay bug fixes.
That is why minimum age should be policy-driven, not dogma.
Use exceptions for:
- actively exploited security fixes
- emergency vendor patches
- packages owned and released by your own organization
- releases that have already been manually reviewed
- tightly pinned internal mirrors where artifacts are scanned and promoted deliberately
The point is to slow blind adoption, not to block urgent remediation.
Practical Implementation
Dependabot
GitHub’s Dependabot supports a cooldown option for version updates. Security updates are excluded, which is the right default: you usually want vulnerability fixes to move faster than routine feature updates.
version: 2updates: - package-ecosystem: "npm" directory: "/" schedule: interval: "daily" cooldown: default-days: 3 semver-major-days: 7 semver-minor-days: 3 semver-patch-days: 1This does not make updates safe. It gives review, registry abuse detection, and community reporting time to catch up.
Renovate
Renovate supports minimumReleaseAge. For npm, Renovate’s own documentation uses a three-day example because packages less than 72 hours old can still be unpublished from the npm registry.
{ "prCreation": "not-pending", "internalChecksFilter": "strict", "packageRules": [ { "matchDatasources": ["npm"], "minimumReleaseAge": "3 days" } ]}For high-risk ecosystems, use package rules. A build plugin that runs arbitrary install scripts should not follow the same policy as a small CSS patch.
CI/CD
CI systems should not resolve fresh dependency versions during release builds unless that is an explicit design decision.
For release pipelines:
- use lockfiles and fail if the lockfile changes unexpectedly
- pin GitHub Actions to full-length commit SHAs where practical
- separate pull request workflows from release workflows
- avoid sharing caches across untrusted and trusted workflow boundaries
- use OIDC (OpenID Connect, the short-lived token identity behind trusted publishing) instead of long-lived package tokens
- require review for changes under
.github/workflows/
The goal is simple: a new package should not become a production artifact merely because a resolver found it first.
Developer Workstations
Developer endpoints need a softer version of the same policy.
Start with visibility:
code --list-extensions --show-versionsnpm config get ignore-scriptsgit config --global --get-regexp urlThen define what is allowed:
- approved editor extension list
- no automatic installation of newly published extensions on sensitive workstations
- review for extensions that access source control, terminals, credentials, or AI-agent configuration
- separate throwaway environments for testing unfamiliar packages
- package manager settings that prevent install-time scripts where the workflow allows it
This is where many teams fail. They govern production deployment but leave the developer workstation as a private plugin marketplace with cloud credentials.
A Detection Angle
Minimum age is a prevention control, but it also gives defenders better detection points.
Alert on:
| Signal | Why It Matters |
|---|---|
| Dependency update to a version published less than 24 hours ago | Possible early adoption of a malicious release |
| New editor extension version installed across many endpoints at once | Auto-update blast radius |
| Release workflow resolving dependencies instead of using a checked-in lockfile | Build is not reproducible |
New id-token: write permission in GitHub Actions | Expands OIDC token exposure |
| Workflow change plus package publish in the same short window | Common supply chain compromise pattern |
| Install-time script added to a dependency update | Direct execution path during install |
If you have a software asset inventory, add package age to it. If you have EDR telemetry, watch developer tools touching credential stores shortly after dependency or extension updates.
What To Do This Week
- List every place that can install code automatically: dependency bots, CI, package managers, devcontainers, editor extensions, browser extensions, AI coding tools, and internal templates.
- Add a default 24-72 hour cooldown for routine dependency updates.
- Exempt security updates from the slow path, but require evidence that they are actually security fixes.
- Disable automerge for new major and minor dependency releases unless minimum age has passed.
- Pin release workflows and make lockfile drift fail the build.
- Inventory VS Code extensions and block unmanaged auto-update on sensitive developer machines.
- Rotate long-lived package publishing tokens toward OIDC or another short-lived identity model.
You do not need a perfect supply chain program to start. You need to stop being the first uncontrolled install after a package hits the registry.
Related Posts
- GitHub’s VS Code Extension Breach: What We Know, What We Don’t, and How to Defend - why editor extensions belong inside the developer supply chain threat model.
- GitHub Finally Puts a Human in the Loop: npm Staged Publishing Explained - the publication-side control that pairs well with install-side cooldowns.
- The Cache That Bites Back: GitHub Actions Cache Poisoning Attacks - how trusted automation can reuse poisoned artifacts.
- Miasma and Mini Shai-Hulud: When npm Malware Learned to Persist in AI Coding Agents - why agent and editor configuration must be reviewed like code.
Sources
- TechRadar: The developer device is the new supply chain attack blind spot
- TechRadar: CISA warns that Nx Console and GitHub repositories were abused in supply chain compromises
- GitHub Docs: Dependabot options reference - cooldown
- Renovate Docs: minimumReleaseAge
- GitHub Docs: Secure use reference for GitHub Actions
- npm Docs: Trusted publishing for npm packages