Automated Dependency Updates with Supply Chain Security
How to set up Renovate or Dependabot with cooldown policies that complement pnpm's minimumReleaseAge: automated patches without opening the door to compromised packages.
The previous post covered static supply chain defenses: tool pinning, pnpm workspace settings, CI hardening. But one gap remained: dependency updates. Manual updates mean either falling behind on security patches or adopting new releases the moment they ship. Neither works.
Automated dependency bots solve the velocity problem. A cooldown reduces exposure to attacks discovered after publication, but it cannot guarantee that a malicious release will be found before adoption.
Note
Fact-checked on 2026-07-16 against pnpm 11.10.0 and the current Renovate and Dependabot documentation.
The exposure window
In September 2025, the Shai-Hulud attack compromised over 500 npm packages in a coordinated campaign1. Malicious versions were published, and projects with automated updates that had no cooldown window adopted them within minutes. The attack was discovered and the malicious versions removed within hours, but projects that adopted an affected release before detection were already exposed.
A cooling-off period creates time for registries, maintainers, researchers, and users to identify a malicious release before automated adoption. Detection time varies from hours to much longer, and I found no aggregate evidence that supports a universal 24-hour threshold. The values below are policy choices that trade patch latency for an additional observation window.2
How Cooldowns Work
There are three layers of cooldown in a typical JavaScript project:
| Layer | Tool | Coverage | What it does |
|---|---|---|---|
| Package manager | pnpm minimumReleaseAge | Full tree (transitive too) | Blocks install of packages published less than N minutes ago |
| Update bot | Renovate minimumReleaseAge or Dependabot cooldown | Direct dependencies only | Delays PR creation until a package version is N days old |
| CI gate | StepSecurity npm Package Cooldown | PR-level | Blocks merge if a PR introduces a version published within N days |
The package manager setting catches transitive dependencies that the update bot doesn’t manage. The CI gate catches manual pnpm add commands that bypass the bot entirely.
Renovate Configuration
Renovate’s cooldown is configured with minimumReleaseAge:
{
$schema: "https://docs.renovatebot.com/renovate-schema.json",
extends: ["config:recommended"],
minimumReleaseAge: "3 days",
minimumReleaseAgeBehaviour: "timestamp-required",
}
Renovate will not create a PR for any package version published less than 3 days ago. If the latest release is too fresh, it picks the most recent version that satisfies the age requirement.
For security-specific updates, I can create a package rule that bypasses the cooldown:
{
packageRules: [
{
matchUpdateTypes: ["pin", "digest"],
minimumReleaseAge: "0 days",
description: "Allow immediate pin and digest updates",
},
],
}
Renovate’s minimumReleaseAge only applies to direct dependencies3. pnpm’s minimumReleaseAge fills the gap for transitive dependencies, the ones pulled in by your dependencies, which Renovate does not cover, since it applies to the full dependency tree during resolution.
Dependabot Configuration
Dependabot’s equivalent is the cooldown option:
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
cooldown:
default-days: 3
semver-major-days: 30
semver-minor-days: 7
semver-patch-days: 3
The semver-specific overrides are worth setting; major version bumps warrant a longer cooling-off period since they’re more likely to introduce breaking changes or unexpected behavior.
Dependabot’s cooldown also only applies to direct dependencies4. Like Renovate, it complements pnpm’s minimumReleaseAge rather than replacing it.
The Gap: Transitive Dependencies
pnpm’s minimumReleaseAge manages transitive dependencies during resolution, regardless of whether the dependency is direct or transitive. If a package you depend on adds a new transitive dependency that was published minutes ago, neither Renovate nor Dependabot will catch it, but pnpm will.
The two layers need each other:
- Renovate/Dependabot → creates PRs, manages direct dependency updates, respects its own cooldown
- pnpm
minimumReleaseAge→ catches transitive dependencies, applies at install time, covers the full tree
A layered configuration
A setup that preserves the three cooldown layers and keeps vulnerability detection separate:
- pnpm-workspace.yaml:
minimumReleaseAge: 1440applies a one-day release-age check during full-tree resolution. - Renovate or Dependabot: a three-day cooldown delays proposed direct-dependency updates.
- CI release-age gate: StepSecurity npm Package Cooldown, or an equivalent check, evaluates versions introduced by a pull request.
- CI vulnerability gate:
pnpm audit --prod --audit-level highchecks the resolved tree for known advisories. It does not enforce release age.
The one-day and three-day values are starting points for this threat model, not evidence-backed universal thresholds. Projects that prioritize emergency patch latency can use shorter windows or reviewed exceptions. Projects with slower release requirements can choose longer windows.
Coverage and tradeoffs
Renovate and Dependabot apply their cooldowns to dependencies they manage from manifests. pnpm applies minimumReleaseAge while resolving the full tree, including transitive packages. The pull-request gate covers manual changes that bypass the bot. pnpm audit answers a separate question: whether the resolved tree contains a vulnerability already present in the advisory database.
What’s Next
Automated updates handle the “get patches faster” problem. But the config that supports them, exclusion lists, allowlists, trust policies, can become stale as the dependency tree evolves. The next post covers keeping supply chain exclusions honest.
References
- Renovate
minimumReleaseAge. Cooldown for Renovate-managed updates. - Dependabot
cooldown. Cooldown for Dependabot-managed updates. - pnpm
minimumReleaseAge. Full-tree cooldown at install time. - pnpm
minimumReleaseAgeExclude. Exceptions for packages that need immediate updates. - StepSecurity npm Package Cooldown. CI-level merge gate.
- GitGuardian: Renovate & Dependabot supply chain analysis. Attack case studies.
- Shai-Hulud attack overview. Coordinated npm compromise campaign.
Footnotes
-
The full campaign analysis is Socket’s Shai-Hulud incident report. The attacker targeted Red Hat cloud service packages, deploying malicious versions that stole cloud credentials from CI pipelines. The campaign went undetected until automated behavioral analysis tools caught the anomaly. ↩
-
Individual incident reports provide examples of fast detection, but they do not establish the distribution of npm compromise detection times. I use one day as a project policy that adds an observation window while keeping routine updates moving. It should not be read as a statistical safety threshold. ↩
-
Renovate’s
minimumReleaseAgedocumentation notes the scope is limited to the manifests Renovate manages, typicallypackage.jsonand lockfiles. It does not control how the package manager resolves transitive dependencies. ↩ -
Dependabot’s
cooldownoption applies only to the direct dependencies referenced in the manifest file. GitHub’s documentation confirms this limitation. ↩
This post was written with AI assistance.