How Dependabot Missing Cooldown Happens in GitHub Actions and How to Fix It
Introduction
The .github/dependabot.yml file is the heartbeat of automated dependency management for millions of GitHub repositories. It tells Dependabot which package ecosystems to watch, how often to check for updates, and how to label the resulting pull requests. But a subtle misconfiguration — one that is easy to overlook — can quietly expose a Node.js project and all of its downstream consumers to supply chain attacks: the absence of a cooldown period.
In this repository's Dependabot configuration, both the npm and github-actions ecosystem entries were configured to check for updates on a weekly schedule with no restriction on how new a package version could be before Dependabot proposed it. That means a package published at 9:00 AM on Monday could appear in an automated pull request by the next scheduled run — before a single security researcher has had a chance to flag it as compromised.
The Vulnerability Explained
What the original configuration looked like
Before the fix, the relevant portion of .github/dependabot.yml (starting at line 3) looked like this:
# .github/dependabot.yml (before fix)
updates:
- package-ecosystem: 'npm'
directory: '/'
schedule:
interval: 'weekly'
labels:
- 'dependencies'
- 'skip changeset'
- package-ecosystem: 'github-actions'
directory: '/'
schedule:
interval: weekly
labels:
- 'dependencies'
- 'skip changeset'
Neither the npm entry nor the github-actions entry contains a cooldown block. This is the exact pattern that the Semgrep rule package_managers.dependabot.dependabot-missing-cooldown.dependabot-missing-cooldown matched at line 3 of the file.
Why the absence of a cooldown is dangerous
When Dependabot has no cooldown configured, it will propose an update to a package version as soon as that version appears on the registry (subject only to the check schedule). This creates a critical window of risk rooted in how supply chain attacks actually work:
- Typosquatting and account takeovers: An attacker publishes a malicious version of a popular package (or hijacks a maintainer's npm account) and pushes a backdoored release. With no cooldown, Dependabot opens a PR within days.
- Dependency confusion attacks: A malicious package with the same name as an internal package is published to the public registry. Dependabot immediately surfaces it.
- Unstable releases: A maintainer accidentally publishes a broken version. Without a cooldown, that broken version is proposed before it can be yanked or patched.
Because this is a Node.js library, the blast radius extends beyond this repository. Downstream consumers who depend on this package could inherit a compromised transitive dependency if a malicious update were merged without adequate review time.
A concrete attack scenario
Imagine an attacker compromises the npm credentials of a maintainer for a popular utility package that this project depends on. At 2:00 AM UTC, the attacker publishes version 3.4.1 containing a credential-harvesting script. Without a cooldown, Dependabot's next weekly run generates a pull request titled "Bump utility-package from 3.4.0 to 3.4.1." A developer, seeing only a minor patch bump and a green CI run (the malicious code may not trigger tests), merges the PR. The security community does not flag the compromised version until 36 hours later — too late for this project.
A 7-day cooldown would have meant that 3.4.1 was never even proposed until day 7, by which time the npm security team would have unpublished the malicious version and the community would have issued warnings.
The Fix
The fix is four lines of YAML — two lines added to each ecosystem entry — but the security impact is significant.
Before and after
Before (vulnerable):
- package-ecosystem: 'npm'
directory: '/'
schedule:
interval: 'weekly'
labels:
- 'dependencies'
- 'skip changeset'
After (fixed):
- package-ecosystem: 'npm'
directory: '/'
schedule:
interval: 'weekly'
cooldown:
default-days: 7
labels:
- 'dependencies'
- 'skip changeset'
The same cooldown block was added to the github-actions ecosystem entry:
Before (vulnerable):
- package-ecosystem: 'github-actions'
directory: '/'
schedule:
interval: weekly
labels:
- 'dependencies'
- 'skip changeset'
After (fixed):
- package-ecosystem: 'github-actions'
directory: '/'
schedule:
interval: weekly
cooldown:
default-days: 7
labels:
- 'dependencies'
- 'skip changeset'
Why both ecosystems needed the fix
It is important to note that both the npm and github-actions entries were updated. GitHub Actions workflows are themselves a supply chain attack surface: a compromised Action (e.g., a hijacked actions/checkout or a third-party Action) could exfiltrate secrets, modify build artifacts, or inject malicious code into your CI pipeline. The same 7-day cooldown logic applies equally to both ecosystems.
What default-days: 7 actually does
The cooldown.default-days setting instructs Dependabot to ignore any package version that was published fewer than 7 days ago. It will continue to monitor for updates, but it will not open a pull request for a version until that version has been publicly available for at least a week. This gives:
- The npm security team and community time to review and flag malicious releases
- Automated security scanners (Snyk, OSV, GitHub Advisory Database) time to index new vulnerabilities
- The package maintainer time to yank or patch a bad release before it propagates
You can increase this value beyond 7 days for higher-risk ecosystems or reduce it for ecosystems with more trusted supply chains — but 7 days is the widely recommended baseline.
Prevention & Best Practices
1. Always define cooldown for every ecosystem entry
Any updates entry in dependabot.yml without a cooldown block is a potential supply chain risk. Treat the absence of cooldown the same way you would treat the absence of input validation: a missing control, not a safe default.
# Recommended baseline for any ecosystem
cooldown:
default-days: 7
2. Use semver-specific cooldowns for major versions
Dependabot's cooldown configuration also supports per-semver-type overrides. You might want a longer cooldown for major version bumps, which carry higher risk of breaking changes or supply chain tampering:
cooldown:
default-days: 7
semver-major-days: 14 # Extra caution for major bumps
3. Combine cooldown with allow and ignore rules
Cooldown is one layer of defense. Pair it with explicit allow lists (only update packages you explicitly approve) and ignore rules for packages that require manual review:
allow:
- dependency-type: 'direct'
cooldown:
default-days: 7
4. Enable Dependabot security alerts alongside version updates
Version update cooldowns protect against newly published malicious packages. Dependabot security alerts (configured separately via dependabot_security_updates) respond to known CVEs and should remain unrestricted by cooldown so that critical patches are not delayed.
5. Use static analysis to enforce this in CI
The Semgrep rule that caught this issue can be run in your CI pipeline to prevent regressions:
semgrep --config "p/semgrep-rules" .github/dependabot.yml
Adding this check ensures that any future modification to dependabot.yml that removes the cooldown block will fail the build.
Relevant standards
- CWE-1104: Use of Unmaintained Third-Party Components — directly applicable when unvetted packages are automatically adopted
- OWASP A06:2021 – Vulnerable and Outdated Components — the supply chain risk of unreviewed dependency updates falls squarely in this category
- SLSA (Supply Chain Levels for Software Artifacts) — recommends controls at every stage of the dependency pipeline, including a review window for new versions
Key Takeaways
- Both ecosystem entries in
dependabot.ymllacked acooldownblock — thenpmentry at the top of the file and thegithub-actionsentry below it were both vulnerable, meaning the CI pipeline and the runtime dependencies were equally exposed. - A 7-day cooldown is not just a best practice — it is a concrete defense against the "zero-day publish" attack vector, where a malicious package version is proposed before the security community can react.
- GitHub Actions are a supply chain attack surface too — the
github-actionsecosystem entry needed the same fix asnpm; compromised Actions can exfiltrate CI secrets and tamper with build artifacts. - This Node.js library's downstream consumers were also at risk — because the project is a library, any malicious transitive dependency merged here could propagate to every application that installs this package.
- Static analysis (Semgrep) can detect this configuration gap automatically — the rule
package_managers.dependabot.dependabot-missing-cooldown.dependabot-missing-cooldownmatched this pattern at line 3 of the file, demonstrating that YAML-level security misconfigurations are tractable to automated tooling.
How Orbis AppSec Detected This
- Source: The
updatesentries in.github/dependabot.yml(lines 3 and 11) define the package ecosystems Dependabot monitors. Without acooldownblock, any newly published package version immediately becomes a candidate for an automated PR. - Sink: Dependabot's version update engine — which opens pull requests proposing dependency upgrades — is the "sink" here. Without a cooldown gate, it will surface versions published seconds ago.
- Missing control: The
cooldownblock (specificallydefault-days: 7) was entirely absent from both thenpmandgithub-actionsecosystem entries, meaning there was no minimum-age requirement for proposed package versions. - CWE: CWE-1104 — Use of Unmaintained Third-Party Components (the broader category that encompasses unvetted dependency adoption).
- Fix: A
cooldown: default-days: 7block was inserted into both thenpmandgithub-actionsentries in.github/dependabot.yml, enforcing a 7-day minimum age for any package version before Dependabot proposes it.
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 period in dependabot.yml is easy to overlook — it is an absence of configuration rather than a piece of obviously wrong code. But for a Node.js library with downstream consumers, it represents a real and exploitable gap in supply chain security. The fix is minimal: four lines of YAML across two ecosystem entries. The protection it provides — a 7-day window for the security community to vet newly published packages before they are proposed for adoption — is disproportionately large relative to the effort.
The next time you configure Dependabot for a new repository, make cooldown: default-days: 7 part of your standard template. And consider running Semgrep's Dependabot ruleset in CI to ensure that this control is never accidentally removed.