Note: This post covers a
dependabot-missing-cooldownfinding in.github/dependabot.yml. The PR referenced in the References section applied a related hardening change totools/release.cjsas part of the same security sweep on this repository.
Introduction
In this repository, we discovered a high-severity dependabot-missing-cooldown misconfiguration in .github/dependabot.yml. The configuration told Dependabot to keep an eye on ecosystems like npm and github-actions, but it never set a cooldown period. That means the moment a maintainer (or an attacker who compromised a maintainer's account) published a new package version, Dependabot could open a pull request proposing that exact version — with zero delay for the community to catch anything wrong with it.
This might sound like a minor scheduling detail, but supply-chain attacks specifically exploit that zero-delay window. Real-world incidents like event-stream, ua-parser-js, and various typosquatted npm packages showed that malicious code is often shipped and then removed or patched within hours to days. If your CI pipeline auto-merges Dependabot PRs, or if a developer reviews them quickly and trusts the "latest is safest" assumption, a missing cooldown turns your dependency bot into an unwitting attack vector.
The Vulnerability Explained
Dependabot version updates work by periodically checking each configured package-ecosystem for newer releases and opening a PR to bump the dependency. Without a cooldown setting, there is no minimum age requirement — a version published one minute ago is treated exactly the same as a version that has been stable and battle-tested for months.
A vulnerable dependabot.yml looks something like this:
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
Notice there's nothing here that tells Dependabot to wait. Each package-ecosystem block just defines what to watch and how often to check — not how long to trust a new release before recommending it.
Attack scenario
- An attacker compromises the npm account of a maintainer for a transitive dependency used by this project (a common and repeatedly observed attack pattern).
- The attacker publishes a new patch version containing an obfuscated post-install script that exfiltrates environment variables or CI secrets.
- Within hours, Dependabot's scheduled scan detects the "newer" version and opens a PR bumping the dependency.
- A developer, trusting the automated tooling, approves and merges the PR — or worse, an auto-merge rule takes care of it — before the malicious package is pulled from the registry or flagged by the security community.
- The malicious code now runs in CI, in production builds, or in every downstream consumer of this library.
Because this is a library (per the threat model), the blast radius extends beyond this repository: every application that depends on it inherits whatever gets merged through this exact update path.
The Fix
The remediation is small in size but meaningful in effect: add a cooldown block with default-days: 7 to every package-ecosystem entry under updates.
Before:
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
After:
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
cooldown:
default-days: 7
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
cooldown:
default-days: 7
With cooldown.default-days: 7 in place, Dependabot will not propose a version until it has been publicly available for at least seven days. That window gives the ecosystem — security researchers, registry maintainers, automated malware scanners, and the broader developer community — time to flag a bad release before your CI even considers it. Seven days is GitHub's documented default recommendation and a reasonable balance between staying current and staying safe; teams with stricter compliance needs can tune default-days (or use semver-major-days, semver-minor-days, semver-patch-days for finer control) per ecosystem.
This is a config-only change — no application code paths are touched, and legitimate, vetted updates still flow through normally once the cooldown window passes. It doesn't block bad actors outright, but it removes the "first mover" advantage that made rapid-fire dependency bumps risky.
Prevention & Best Practices
- Always set a
cooldownblock independabot.ymlfor everypackage-ecosystementry — don't assume the default behavior is safe; without explicit configuration, there is no cooldown at all. - Pair cooldowns with review requirements. Don't auto-merge Dependabot PRs for production dependencies; require at least one human review, especially for packages with install scripts (npm
postinstall, etc.). - Use
ignoreandallowrules to scope Dependabot to the ecosystems and directories you actually maintain, reducing noise and unnecessary exposure. - Enable lockfile-only updates or vendor auditing where possible (
npm audit,pip-audit, OSV-Scanner) as a second layer of defense alongside the cooldown. - Audit existing
.github/dependabot.ymlfiles across all repositories in your organization — this is a config file, so it's easy for a single unreviewed template to propagate the same gap everywhere. - Use scanners that understand YAML security configs (Semgrep's config rules, Orbis AppSec) to catch this class of issue automatically, since it's invisible to typical application-level SAST tools.
Key Takeaways
.github/dependabot.ymlhadupdatesentries fornpmandgithub-actionswith nocooldownblock, meaning zero delay between a package's publication and Dependabot recommending it.- The fix adds
cooldown: { default-days: 7 }to eachpackage-ecosystementry — this must be repeated per entry, not set once globally. - A missing cooldown is a supply-chain risk, not a code-execution bug — it widens the window in which a compromised or unstable release can reach your dependency tree via an automated, trusted bot.
- Seven days is GitHub's own recommended minimum; teams handling sensitive data or regulated workloads may want longer cooldowns for major/minor bumps.
- Configuration files deserve the same security scrutiny as application code — this class of finding won't show up in typical code-level SAST scans.
How Orbis AppSec Detected This
- Source: The
updateslist in.github/dependabot.yml, specifically eachpackage-ecosystementry (npm,github-actions) that Dependabot polls for new releases. - Sink: Dependabot's automated PR-creation pipeline, which opens a pull request the moment it detects a newer published version, with no age filtering applied.
- Missing control: No
cooldownblock (default-daysor per-semver-level day counts) was defined, so there was no minimum "aging" period before a new release could be proposed. - CWE: CWE-829 — Inclusion of Functionality from Untrusted Control Sphere.
- Fix: Added a
cooldown: { default-days: 7 }block to everypackage-ecosystementry underupdates, requiring newly published versions to wait seven days before Dependabot proposes them.
Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.
Conclusion
A missing cooldown in dependabot.yml is easy to overlook because it's not "vulnerable code" in the traditional sense — it's a configuration gap that quietly removes a safety buffer between package publication and adoption. Given how frequently npm and other registries have been used as delivery mechanisms for supply-chain attacks, giving the ecosystem seven days to catch a bad release before your automation proposes it is a cheap, high-leverage control. Treat your dependency-update tooling with the same scrutiny you'd apply to any other trust boundary in your system, and make sure every package-ecosystem entry in every repo has an explicit cooldown set.