Why a config file most teams never look at twice matters
.github/dependabot.yml is the kind of file a lot of teams write once and never revisit. It quietly tells GitHub which ecosystems to scan, how often, and where. But because it controls what gets automatically proposed into your codebase, it's also a prime piece of supply-chain infrastructure — and this repository's version was missing a critical safety valve: a cooldown period.
Without a cooldown block, Dependabot behaves like an eager intern who opens a PR the instant a new package version hits the registry — even if that version was published thirty seconds ago by an attacker who just took over a maintainer's npm account.
The Vulnerability Explained
Here's what a typical vulnerable .github/dependabot.yml looks like — no cooldown key anywhere:
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
There is no delay logic. As soon as GitHub's registry crawler sees a new release for any dependency tracked by these package-ecosystem entries, Dependabot opens a pull request proposing the bump — regardless of how old (or new) that release is.
That matters because the software supply chain has repeatedly shown that "newly published" and "safe" are not the same thing:
event-stream(2018) — a maintainer handed off the npm package to an unknown contributor who slipped in a bitcoin-wallet-stealing dependency in a minor version bump.ua-parser-js(2021) — a compromised npm account pushed a malicious patch release that installed cryptominers and credential stealers on any machine that rannpm installshortly after.xz-utils(2024) — a multi-year social-engineering campaign culminated in a backdoored release tag that, had it been auto-adopted by CI pipelines without delay, could have propagated a remote-code-execution backdoor across thousands of Linux builds.
In every one of these cases, the malicious version was live for hours to days before the community noticed and yanked it or published an advisory. A Dependabot config with no cooldown will happily open (and, if auto-merge is configured, merge) a PR to adopt that version during exactly that vulnerable window — long before a CVE, GHSA advisory, or npm takedown exists to stop it.
Attack scenario for this repo specifically: an attacker compromises the npm account behind a dependency used somewhere in this project's package.json, publishes a trojanized patch release, and within the daily Dependabot scan cycle a PR titled Bump <package> from x.y.z to x.y.z+1 shows up. If CI is green (the malicious payload is often designed to pass tests) and a reviewer trusts the "routine dependency bump" label enough to merge quickly, the backdoor is now in main.
The Fix
The remediation is to add a cooldown block with default-days: 7 to every package-ecosystem entry under updates:
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 this in place, Dependabot will not propose a version that was published fewer than seven days ago. That one-week window is enough time for:
- Security researchers and the community to spot obviously malicious releases and file advisories.
- Package registries (npm, RubyGems, PyPI, etc.) to yank or flag compromised versions.
- CI/telemetry from other users of the same package to surface anomalies before your repo touches it.
This fix landed as part of a broader supply-chain hardening pass in this repository. In the same effort, action/action.yml was updated to remove mutable, floating tag references from its steps:
# before — mutable tag, silently repointable by the action owner
- uses: actions/setup-node@v7
with: { node-version: '22' }
# after — pinned to an immutable commit SHA, with the tag kept as a comment for readability
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with: { node-version: '22' }
The same pattern was applied to actions/upload-artifact@v7, which was pinned to 043fb46d1a93c77aae656e7c1c64a875d1fc6a0a. These two hardening changes attack the same class of risk from different angles: SHA-pinning stops an attacker from silently repointing a tag you already depend on (as happened in the tj-actions/changed-files and reviewdog incidents), while the Dependabot cooldown stops you from voluntarily adopting a brand-new, unvetted version the moment it's published. You need both — pinning without a cooldown still leaves you exposed the first time Dependabot proposes moving the pin forward to a version that's hours old.
Prevention & Best Practices
- Always set a
cooldownon everypackage-ecosystementry in.github/dependabot.yml. GitHub's docs recommenddefault-days: 7as a sane baseline; security-sensitive ecosystems (likegithub-actions, which runs with elevated CI permissions) can justify longer windows. - Pin GitHub Actions to full 40-character SHAs, not tags or branches, and let Dependabot bump the SHA (which is exactly what a properly cooled-down config protects you from doing prematurely).
- Don't auto-merge Dependabot PRs blindly. Even with a cooldown, require CI plus at least a lightweight human glance at the diff for anything touching lockfiles or
node_modules/vendortrees. - Monitor registry advisories (GitHub Security Advisories, npm's security feed, OSV) so you can react even faster than the cooldown window if something is flagged early.
- Lint your Dependabot config as part of CI. Tools like Semgrep can parse YAML and assert that every
updates[].package-ecosystementry has a correspondingcooldown.default-daysfield.
Relevant standards: this class of issue maps to CWE-1357 (Reliance on Insufficiently Trustworthy Component) and is squarely in scope for the OWASP Software Supply Chain Security guidance.
Key Takeaways
.github/dependabot.ymlin this repo hadpackage-ecosystementries with nocooldownblock, so any freshly published version — malicious or not — could immediately trigger an update PR.- Adding
cooldown: default-days: 7to each ecosystem entry enforces a one-week vetting delay before Dependabot proposes new versions. - This complements, but does not replace, SHA-pinning of GitHub Actions (as seen in the
actions/setup-nodeandactions/upload-artifactchanges inaction/action.yml) — pinning stops silent tag repointing, cooldown stops premature adoption of new releases. - Config-only vulnerabilities like this one are easy to miss in code review because there's no "bad line" to point at — just a missing field — which is exactly why automated scanning of
.github/dependabot.ymlmatters. - A 7-day cooldown is a floor, not a ceiling: consider longer windows for
github-actionsand other high-privilege ecosystems.
How Orbis AppSec Detected This
- Source: A newly published package or GitHub Action version appearing in the upstream registry (npm, RubyGems, GitHub Marketplace, etc.) that Dependabot's scanner picks up.
- Sink: The automatically generated Dependabot pull request that proposes bumping the dependency in the project's manifest/lockfile, which CI then builds and (potentially) a maintainer merges.
- Missing control: No
cooldownblock on thepackage-ecosystementries in.github/dependabot.yml, so there was no minimum age requirement before a version could be proposed. - CWE: CWE-1357 — Reliance on Insufficiently Trustworthy Component.
- Fix: Added a
cooldownblock withdefault-days: 7to eachpackage-ecosystementry underupdatesin.github/dependabot.yml.
Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. [Try Orbis AppSec on your repositories](https://orbisappsec.com