How Missing Dependabot Cooldown Happens in GitHub Actions CI/CD and How to Fix It
Introduction
In this Node.js library's repository, we discovered a high-severity supply chain security misconfiguration at .github/dependabot.yml:7. The Dependabot configuration defined two package ecosystem entries—one for npm and one for github-actions—but neither included a cooldown block. This meant that the moment a new version of any dependency was published to npm or the GitHub Actions marketplace, Dependabot would immediately propose an update PR.
For a Node.js library consumed by downstream projects, this is particularly dangerous. If a maintainer (or an attacker who has compromised a maintainer's account) publishes a malicious version, Dependabot would race to create a pull request within hours. If that PR is auto-merged or quickly approved, the malicious code enters the dependency tree and propagates to every consumer of this library.
The Vulnerability Explained
Here's the original dependabot.yml configuration (simplified for clarity):
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
allow:
- dependency-type: "direct"
schedule:
interval: "weekly"
open-pull-requests-limit: 1
labels:
- "Task"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
labels:
- "Task"
Notice what's absent: there is no cooldown block in either ecosystem entry. The schedule: interval: "weekly" setting only controls how often Dependabot checks for new versions—it does not control how fresh a version can be when it's proposed.
The Attack Scenario
Consider this realistic supply chain attack timeline:
- Day 0, 9:00 AM: An attacker compromises the npm credentials of a maintainer for
lodash(or any direct dependency of this library). - Day 0, 9:05 AM: The attacker publishes
lodash@4.17.22containing a backdoor that exfiltrates environment variables. - Day 0, 10:00 AM: Dependabot's weekly scan runs, detects the new version, and opens a PR titled "Bump lodash from 4.17.21 to 4.17.22."
- Day 0, 10:30 AM: A developer sees the PR, notes it's a patch version from a trusted package, and merges it.
- Day 0, 11:00 AM: The compromised library is published in the next release, affecting all downstream consumers.
The npm ecosystem has seen exactly this pattern. The event-stream incident (2018), ua-parser-js hijack (2021), and colors/faker sabotage (2022) all involved malicious versions that were detected by the community within days—but not within hours.
Without a cooldown, Dependabot operates in that dangerous window between publication and community detection.
Why This Is High Severity
This repository is a Node.js library. Unlike an application that only affects its own deployment, a library vulnerability cascades. Every project that depends on this library inherits its dependency choices. A malicious transitive dependency introduced via Dependabot doesn't just compromise one service—it compromises an entire ecosystem of consumers.
The Fix
The fix adds a cooldown block with default-days: 7 to both package ecosystem entries:
Before (npm ecosystem):
- package-ecosystem: "npm"
directory: "/"
allow:
- dependency-type: "direct"
schedule:
interval: "weekly"
open-pull-requests-limit: 1
labels:
- "Task"
After (npm ecosystem):
- package-ecosystem: "npm"
directory: "/"
allow:
- dependency-type: "direct"
schedule:
interval: "weekly"
cooldown:
default-days: 7
open-pull-requests-limit: 1
labels:
- "Task"
Before (github-actions ecosystem):
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
labels:
- "Task"
After (github-actions ecosystem):
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
cooldown:
default-days: 7
labels:
- "Task"
How the Fix Works
The cooldown configuration tells Dependabot: "Even if you detect a new version, don't propose it until it has been published for at least 7 days." This 7-day quarantine period serves as a community-sourced vetting window:
- Day 1-3: Security researchers and automated scanners (like Socket.dev, Snyk, npm audit) analyze the new version.
- Day 3-5: If the package is malicious, npm typically yanks it and publishes an advisory.
- Day 5-7: The broader community has flagged instability issues or regressions.
By day 7, a package version that has survived without being flagged is substantially more trustworthy than one published minutes ago.
Both ecosystems needed the fix because:
- npm: Protects against compromised JavaScript packages (the most common supply chain attack vector)
- github-actions: Protects against compromised GitHub Actions, which execute with repository secrets and write permissions
Prevention & Best Practices
-
Always configure cooldown in Dependabot: Treat
cooldownas a required field, not optional. A 7-day minimum is recommended; critical infrastructure projects may want 14+ days. -
Combine with other defenses:
- Useallow: dependency-type: "direct"(already present in this config) to limit update scope
- Setopen-pull-requests-limit: 1(already present) to prevent flood attacks
- Enable npm'snpm audit signaturesto verify package provenance -
Never auto-merge dependency updates: Even with a cooldown, require human review of dependency PRs. The cooldown reduces risk but doesn't eliminate it.
-
Use lockfiles and verify integrity: Ensure
package-lock.jsonis committed and that CI validates integrity hashes. -
Monitor for supply chain advisories: Subscribe to GitHub Security Advisories and npm's
@npmcli/arboristaudit feeds. -
Lint your Dependabot configuration: Use Semgrep or similar tools to enforce organizational policies on
dependabot.ymlfiles across all repositories.
Key Takeaways
- A
schedule: interval: "weekly"does NOT provide the same protection as acooldown: default-days: 7—schedule controls check frequency, cooldown controls version age requirements. - Both
npmandgithub-actionsecosystems in this specificdependabot.ymlwere vulnerable—supply chain attacks target actions as well as packages. - This Node.js library's downstream consumers were indirectly exposed—a compromised dependency would propagate to every project using this library.
- The 7-day cooldown aligns with the typical detection window for malicious npm packages—most hijacked packages are flagged within 72 hours, giving a comfortable margin.
- Two lines of YAML per ecosystem entry (
cooldown:anddefault-days: 7) eliminate an entire class of supply chain risk.
How Orbis AppSec Detected This
- Source: Newly published package versions on npm registry and GitHub Actions marketplace
- Sink: Dependabot's automatic PR creation at
.github/dependabot.yml:7(npm ecosystem) and:16(github-actions ecosystem), which proposes immediate adoption of unvetted versions - Missing control: No
cooldownblock to enforce a minimum age requirement on proposed package versions - CWE: CWE-1395 (Dependency on Vulnerable Third-Party Component)
- Fix: Added
cooldown: default-days: 7to both thenpmandgithub-actionspackage ecosystem entries, ensuring a 7-day quarantine before updates are proposed
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
Supply chain security isn't just about scanning your code—it's about controlling the velocity at which unvetted external code enters your project. A missing Dependabot cooldown is a subtle but high-impact misconfiguration that turns your automated dependency management into a potential attack vector. The fix is trivial (two lines of YAML per ecosystem), but the protection is substantial: a 7-day buffer that aligns with the community's ability to detect and flag malicious packages.
For maintainers of Node.js libraries, this is especially critical. Your dependency choices cascade to every downstream consumer. Adding a cooldown period is one of the simplest ways to be a responsible steward of your ecosystem.