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 in GitHub-hosted projects. It tells Dependabot which ecosystems to watch, how often to check for updates, and how to label the resulting pull requests. But a subtle omission in this file — the absence of a cooldown block — can quietly expose your project and everyone who depends on it to one of the most insidious modern threats: supply chain attacks via freshly published packages.
In this repository, a Semgrep scan flagged a high-severity misconfiguration at line 3 of .github/dependabot.yml: neither the npm ecosystem entry nor the github-actions ecosystem entry defined a cooldown period. With a schedule.interval of "daily", Dependabot was configured to surface update proposals for packages the same day they were published — before the security community, package registries, or downstream users had any opportunity to identify problems.
Because this is a Node.js library, the blast radius extends beyond the repository itself. Any downstream consumer who trusts this library's dependency updates inherits the same risk.
The Vulnerability Explained
What does "no cooldown" actually mean?
When Dependabot detects a new version of a package, the default behavior (without a cooldown) is to open a pull request almost immediately. For a repository running on a "daily" schedule, that means a package published at 11:00 PM could have an open update PR by the next morning.
Here is the vulnerable configuration as it existed before the fix:
# .github/dependabot.yml (BEFORE FIX)
version: 2
updates:
- package-ecosystem: "npm"
directories:
- "/"
schedule:
interval: "daily"
labels:
- "npm"
- "Dependabot"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
labels:
- "github-actions"
- "Dependabot"
Notice what is absent: there is no cooldown block under either package-ecosystem entry. This is the root cause.
Why is this dangerous?
The npm ecosystem publishes thousands of new package versions every day. Not all of them are legitimate. Attackers use several well-documented techniques to exploit the window between publication and detection:
- Package hijacking: An attacker gains control of a maintainer's npm account and publishes a malicious version of a widely-used package. The malicious version exists for only hours before it is yanked — but that window is enough.
- Typosquatting / dependency confusion: A malicious package with a name similar to a legitimate one is published, hoping automated tooling will pick it up.
- Protestware / sabotage: A maintainer intentionally introduces destructive code into a new version (as seen with
colors,faker, andnode-ipcin recent years).
In all three scenarios, the first 24–72 hours after publication are the highest-risk window. Security researchers, package registry maintainers, and the broader community typically identify and flag malicious packages within days. A 7-day cooldown means Dependabot waits until after this danger window closes before ever showing the update to your team.
The attack scenario for this specific repository
Because this project runs Dependabot on a "daily" schedule for both npm packages and GitHub Actions, an attacker could:
- Publish a malicious patch version of any npm package listed in this project's
package.json(or a GitHub Action used in its workflows). - Within 24 hours, Dependabot opens a PR proposing the update.
- A developer, seeing a routine-looking dependency bump PR with a green CI badge, merges it.
- The malicious code executes in CI (for Actions) or ships to downstream consumers (for npm packages).
The github-actions ecosystem entry is particularly sensitive: a compromised GitHub Action executing in CI has access to secrets, tokens, and the ability to exfiltrate or tamper with build artifacts.
The Fix
The fix is precise and minimal: a cooldown block with default-days: 7 was added to both ecosystem entries.
# .github/dependabot.yml (AFTER FIX)
version: 2
updates:
- package-ecosystem: "npm"
directories:
- "/"
schedule:
interval: "daily"
cooldown:
default-days: 7
labels:
- "npm"
- "Dependabot"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
cooldown:
default-days: 7
labels:
- "github-actions"
- "Dependabot"
Before vs. After
| Aspect | Before | After |
|---|---|---|
| npm update proposals | Immediate (same day as publish) | 7 days after publish |
| GitHub Actions update proposals | Immediate (same day as publish) | 7 days after publish |
| Exposure to day-zero malicious packages | High | Significantly reduced |
| Lines changed | — | +4 lines (2 per ecosystem entry) |
Why both entries needed the change
It would not be sufficient to add the cooldown to only one ecosystem. Both npm and github-actions entries independently schedule Dependabot runs. An attacker targeting GitHub Actions (which run in CI with elevated permissions) would have the same zero-day window as an attacker targeting npm packages. Each ecosystem entry must independently declare its own cooldown policy.
What default-days: 7 means in practice
The cooldown.default-days value tells Dependabot: "Do not propose an update for a package version until at least N days have passed since that version was published." You can also configure per-semver-range overrides (e.g., a longer cooldown for major versions), but a 7-day default is the recommended baseline from GitHub's own documentation.
Prevention & Best Practices
1. Always define a cooldown in new Dependabot configurations
Whenever you create or update a dependabot.yml, treat cooldown.default-days as a required field, not an optional one. A value of 7 is the GitHub-recommended minimum.
2. Consider higher cooldowns for major version bumps
Major versions introduce breaking changes and are higher-risk targets for supply chain attacks. You can configure this explicitly:
cooldown:
default-days: 7
semver-major-days: 30
3. Combine cooldown with dependency review
GitHub's Dependency Review Action can block PRs that introduce packages with known vulnerabilities. Pairing it with a cooldown gives you both time-based and vulnerability-database-based protection.
4. Use Semgrep to enforce this in CI
The Semgrep rule package_managers.dependabot.dependabot-missing-cooldown.dependabot-missing-cooldown can be added to your CI pipeline to catch missing cooldowns before they reach production:
- name: Semgrep scan
uses: semgrep/semgrep-action@v1
with:
config: >-
p/supply-chain
5. Apply the principle of least privilege to Dependabot PRs
Ensure Dependabot PRs do not have write access to secrets. Use GitHub's Dependabot secrets feature rather than exposing repository secrets directly.
Security Standards Reference
- OWASP A06:2021 – Vulnerable and Outdated Components: Stresses the importance of controlled, vetted dependency updates.
- SLSA (Supply Chain Levels for Software Artifacts): Recommends verification and review windows for third-party dependencies.
- CWE-1104: Use of Unmaintained Third-Party Components — directly applicable to unvetted, freshly published package adoption.
Key Takeaways
- The
npmecosystem entry in.github/dependabot.ymlhad no cooldown, meaning any malicious npm package version could be proposed for adoption within 24 hours of publication on a daily schedule. - The
github-actionsecosystem entry carried the same risk, and a compromised Action executing in CI is particularly dangerous due to its access to secrets and build artifacts. - A 4-line change — adding
cooldown: default-days: 7to each entry — closes the highest-risk window for supply chain attacks without disrupting the dependency update workflow. - This is a Node.js library, so the impact of a compromised dependency is not limited to this repository; it propagates to all downstream consumers.
- Static analysis (Semgrep) can reliably detect this misconfiguration at the YAML level, making it automatable in any CI pipeline.
How Orbis AppSec Detected This
- Source: The
updatesentries in.github/dependabot.ymldefine which package ecosystems Dependabot monitors and how quickly it acts on newly published versions. - Sink: The absence of a
cooldownblock in both thenpm(line 3+) andgithub-actionsecosystem entries means Dependabot immediately surfaces new package versions as update candidates — the dangerous "sink" being the automated PR creation for unvetted, freshly published packages. - Missing control: No
cooldown.default-daysvalue was set, removing the only time-based gate between package publication and Dependabot update proposal. - CWE: CWE-1104 — Use of Unmaintained Third-Party Components (extended to insufficient supply chain controls over newly published versions).
- Fix: Added
cooldown: default-days: 7to both thenpmandgithub-actionspackage ecosystem entries in.github/dependabot.yml, enforcing a 7-day waiting period before any new package version is proposed as an update.
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 configuration is easy to overlook — it is not a code bug, it is an absence of a safety control in a configuration file. But for a Node.js library with a daily update schedule, that absence meant every newly published package version was immediately eligible to be proposed as an update, including packages published by attackers exploiting the critical first-day window.
The fix is small: four lines of YAML. The protection it provides is substantial: a 7-day buffer that lets the security community, package registries, and automated scanners identify and flag malicious packages before they ever reach your team's review queue.
Supply chain security is not just about scanning your current dependencies — it is about controlling how and when new dependencies enter your project. Cooldown periods are one of the simplest and most effective controls available, and they should be standard practice in every dependabot.yml configuration.