How Dependabot Missing Cooldown Configuration Happens in GitHub Actions and How to Fix It
The .github/dependabot.yml file is the quiet workhorse of dependency hygiene — it keeps your packages up to date so you don't have to. But in a Node.js library project, this same file contained a subtle but high-severity misconfiguration: none of its three package-ecosystem entries defined a cooldown period. That means Dependabot was configured to immediately propose updates to any newly published package version, regardless of how recently it appeared on a registry. This blog post explains exactly what that means, why it's dangerous, and how a targeted fix closes the gap.
The Vulnerability Explained
What Was Actually Missing
The vulnerable .github/dependabot.yml defined three package ecosystems — github-actions, npm, and composer — each with a monthly update schedule and a limit of 10 open pull requests. Here is what the configuration looked like before the fix:
# .github/dependabot.yml (before fix)
updates:
- package-ecosystem: github-actions
directory: '/'
schedule:
interval: monthly
open-pull-requests-limit: 10
- package-ecosystem: npm
directory: '/'
schedule:
interval: monthly
open-pull-requests-limit: 10
- package-ecosystem: composer
directory: '/'
schedule:
interval: monthly
open-pull-requests-limit: 10
Notice what's absent from every single block: a cooldown configuration. Without it, Dependabot will happily propose an update to a package version published just hours or even minutes ago — well before the open-source community, security researchers, or automated malware scanners have had a chance to review it.
Why This Is a Real Threat
The software supply chain has become a prime attack vector. Attackers use several techniques to exploit projects with no cooldown protection:
- Dependency confusion attacks: An attacker publishes a malicious package with the same name as a private internal package, hoping automated tooling picks it up immediately.
- Typosquatting with timing attacks: A malicious package is published right before a legitimate package's expected release, hoping to be surfaced first.
- Compromised maintainer accounts: A legitimate package's maintainer account is hijacked and a backdoored version is pushed. Without a cooldown, Dependabot opens a PR within the same Dependabot check cycle.
- Unstable releases: Even non-malicious packages sometimes publish broken versions that are quickly yanked. A cooldown prevents these from ever reaching your codebase.
The Attack Scenario for This Repository
This project is a Node.js library — meaning its downstream consumers (other developers who install this package) inherit its dependency risks. Here is a concrete scenario:
- An attacker identifies a popular
npmpackage that this library depends on. - The attacker compromises the maintainer's npm credentials and publishes a backdoored
v2.3.1. - Dependabot runs its next monthly check and immediately opens a PR: "Bump
some-packagefrom 2.3.0 to 2.3.1". - A developer, trusting the automated PR, merges it without deep scrutiny (this is extremely common — Dependabot PRs are often auto-merged or rubber-stamped).
- The backdoored version ships in the next library release and propagates to every downstream consumer.
With a 7-day cooldown, step 3 never happens — because within 7 days, the malicious version would almost certainly have been detected, reported, and yanked from the registry.
Why a Monthly Schedule Alone Is Not Enough
It's tempting to think: "We already check monthly — that's conservative enough." But the schedule.interval only controls when Dependabot runs its check, not how old a package version must be before it's considered. If Dependabot runs its monthly check on the same day a malicious package is published, it will surface it immediately. The cooldown is an orthogonal protection that filters out versions younger than N days, regardless of when the check runs.
The Fix
The fix added a cooldown block with default-days: 7 to all three ecosystem entries. Here is the exact diff:
# .github/dependabot.yml (after fix)
updates:
- package-ecosystem: github-actions
directory: '/'
schedule:
interval: monthly
open-pull-requests-limit: 10
+ cooldown:
+ default-days: 7
- package-ecosystem: npm
directory: '/'
schedule:
interval: monthly
open-pull-requests-limit: 10
+ cooldown:
+ default-days: 7
- package-ecosystem: composer
directory: '/'
schedule:
interval: monthly
open-pull-requests-limit: 10
+ cooldown:
+ default-days: 7
Why All Three Ecosystems Needed the Fix
Each package-ecosystem entry is evaluated independently by Dependabot. A cooldown on the npm block does not protect the github-actions or composer blocks. Since all three were missing the configuration, all three required the fix:
github-actions: GitHub Actions workflows can execute arbitrary code in your CI/CD pipeline. A malicious action version could exfiltrate secrets or tamper with build artifacts.npm: The primary dependency ecosystem for this Node.js library. This is the highest-risk surface given the project type.composer: PHP dependencies that may be used in tooling or server-side components of the project.
What cooldown: default-days: 7 Actually Does
The default-days value tells Dependabot to ignore any package version that was published fewer than 7 days ago. So if lodash releases 4.18.0 today, Dependabot will not propose that update until at least 7 days have passed. The default prefix means this applies to all packages in that ecosystem unless overridden with more specific rules (e.g., you could set a longer cooldown for specific packages that have a history of problematic releases).
Prevention & Best Practices
Always Define Cooldowns When Configuring Dependabot
Any time you create or modify a .github/dependabot.yml file, treat the cooldown block as mandatory, not optional. A 7-day default is a reasonable baseline for most projects. For high-risk or critical-path dependencies, consider increasing it to 14 or even 30 days.
Consider Ecosystem-Specific Risk
Different ecosystems carry different risk profiles:
| Ecosystem | Risk Level | Recommended Cooldown |
|---|---|---|
npm |
High (large attack surface, frequent typosquatting) | 7–14 days |
github-actions |
High (executes in CI/CD with secret access) | 7–14 days |
composer |
Medium | 7 days |
pip |
High | 7–14 days |
maven |
Medium | 7 days |
Pair Cooldowns With Other Supply Chain Controls
A cooldown is one layer of defense. Combine it with:
- Dependency pinning: Pin to exact versions or commit SHAs (especially for GitHub Actions).
- Lockfile integrity checks: Use
npm ciinstead ofnpm installin CI to enforce lockfile fidelity. - SBOM generation: Generate a Software Bill of Materials on each release to track what's in your dependency tree.
- Automated PR review policies: Require human review for all Dependabot PRs rather than auto-merging.
- Socket.dev or similar tools: Tools that analyze npm packages for malicious behavior at publish time.
Use Semgrep to Catch This in CI
The Semgrep rule package_managers.dependabot.dependabot-missing-cooldown.dependabot-missing-cooldown can be integrated into your CI pipeline to catch this misconfiguration before it reaches production. Add it to your .semgrep.yml or run it as part of a security gate on PRs that modify .github/dependabot.yml.
OWASP and CWE Alignment
This vulnerability aligns with:
- CWE-1104: Use of Unmaintained Third-Party Components — the root cause is blindly consuming newly released, unvetted third-party packages.
- OWASP A06:2021 – Vulnerable and Outdated Components: While this OWASP category typically focuses on outdated components, the inverse risk — consuming too-new components without vetting — is equally covered under the spirit of this category.
- SLSA (Supply-chain Levels for Software Artifacts): SLSA Level 2+ requires provenance for all dependencies. A cooldown period is complementary to provenance verification.
Key Takeaways
- All three
package-ecosystementries in.github/dependabot.ymllacked acooldownblock — each one independently exposed the project to immediate uptake of newly published, unvetted packages. - A monthly
schedule.intervaldoes not substitute for a cooldown — the schedule controls check frequency, whilecooldowncontrols minimum package age. They protect against different attack vectors. - GitHub Actions ecosystem is particularly high-risk without a cooldown — a malicious action version executing in CI has direct access to repository secrets and build artifacts.
- This is a Node.js library, meaning supply chain compromises propagate to all downstream consumers, multiplying the blast radius of any single malicious dependency update.
- The fix is three lines of YAML per ecosystem — a minimal change with a significant security payoff that requires no code changes, no test updates, and no behavior modifications.
How Orbis AppSec Detected This
- Source: The
.github/dependabot.ymlconfiguration file at line 8, wherepackage-ecosystementries are defined without any version-age filtering. - Sink: Dependabot's automated PR creation pipeline — the "dangerous call site" here is the moment Dependabot proposes a newly published package version as a dependency update without any temporal gate.
- Missing control: No
cooldownblock was present on any of the threepackage-ecosystementries (github-actions,npm,composer), meaning Dependabot applied zero minimum-age filtering to proposed package versions. - CWE: CWE-1104 — Use of Unmaintained Third-Party Components (extended to cover unvetted newly published components).
- Fix: Added
cooldown: default-days: 7to all three ecosystem entries in.github/dependabot.yml, ensuring no package version younger than 7 days will be surfaced as a Dependabot PR.
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 configuration is easy to overlook — it's not a code bug, it's a configuration omission. But for a Node.js library with downstream consumers, it represents a genuine high-severity supply chain risk. The fix is elegantly simple: six lines of YAML across three ecosystem blocks, each adding cooldown: default-days: 7. This single change ensures that no package version — whether malicious, unstable, or simply too new to be trusted — can be automatically surfaced as a dependency update until it has had at least a week to be scrutinized by the community.
Security configuration files like .github/dependabot.yml deserve the same rigorous review as application code. Treat every missing security option as a potential vulnerability, because in the supply chain threat landscape, it very often is.