Introduction
In a production web service repository, we discovered a high-severity supply chain security gap hiding in plain sight: .github/dependabot.yml at line 3 was configured to automatically propose updates to packages within hours of their publication. The file handles automated dependency management for both npm and GitHub Actions ecosystems, but the absence of a cooldown period created a direct path for attackers to inject malicious code into the build pipeline.
The vulnerable configuration looked like this:
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: daily
open-pull-requests-limit: 10
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: daily
open-pull-requests-limit: 10
Notice what's missing? There's no cooldown block. This means Dependabot would propose an update to ws version 8.18.0 (the package with CVE-2026-48779's denial of service vulnerability) the same day it was published—before the security community could identify and report the issue.
For developers managing CI/CD pipelines, this pattern is especially dangerous because it automates a critical security decision: when to trust a new dependency version.
The Vulnerability Explained
The Specific Problem
The Semgrep scanner flagged this with rule package_managers.dependabot.dependabot-missing-cooldown.dependabot-missing-cooldown, identifying that both package-ecosystem: "npm" and package-ecosystem: "github-actions" entries lacked cooldown configuration. The scanner matched at line 3, the start of the first ecosystem entry.
The vulnerable pattern:
- package-ecosystem: "npm" # Line 3 - flagged location
directory: "/"
schedule:
interval: daily
open-pull-requests-limit: 10
# NO cooldown block here!
How It Could Be Exploited
Here's a concrete attack scenario targeting this specific configuration:
-
Attacker publishes malicious package: An attacker typosquats a popular npm package (like
ws-patchedinstead ofws) or compromises a maintainer account to publish a backdoored version of a legitimate package. -
Zero-day window: The malicious package is published at 9:00 AM UTC. At this point, no security scanners have flagged it, no CVE exists, and the package appears legitimate with proper semantic versioning.
-
Dependabot immediate proposal: Because
interval: dailyruns Dependabot checks every 24 hours, and there's nocooldownto delay new versions, Dependabot detects the "update" during its next run at 2:00 PM UTC—just 5 hours after publication. -
Auto-merge danger: If the repository uses automated merge rules for Dependabot PRs (common in devOps environments), or if developers habitually merge green PRs quickly, the malicious dependency enters the build pipeline within hours.
-
Production compromise: The
wspackage specifically handles WebSocket connections. A malicious version could exfiltrate data from WebSocket messages, create backdoors in connection handlers, or exploit the memory exhaustion vulnerability in CVE-2026-48779 to crash production services.
Real-World Impact
For this web service, the impact was severe:
- Immediate exposure window: Any npm or GitHub Actions update could be adopted before community vetting
- Automated attack surface: The
dailyinterval combined with no cooldown created predictable, automatable exploitation timing - Cascading supply chain risk: A compromised GitHub Action in the workflow could exfiltrate repository secrets, modify source code, or inject malware into build artifacts
The package-lock.json file's mention of ws is particularly relevant—this is a WebSocket library with a history of security issues. A malicious ws update proposed by Dependabot could exploit the very memory exhaustion vulnerability (CVE-2026-48779) that legitimate updates might fix, but with attacker-controlled payload delivery.
The Fix
Specific Changes Made
The fix adds cooldown configuration with default-days: 7 to both package-ecosystem entries:
Before (vulnerable):
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: daily
open-pull-requests-limit: 10
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: daily
open-pull-requests-limit: 10
After (fixed):
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: daily
open-pull-requests-limit: 10
cooldown:
default-days: 7
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: daily
open-pull-requests-limit: 10
cooldown:
default-days: 7
How This Solves the Problem
The cooldown: default-days: 7 configuration creates a mandatory 7-day embargo period after any package's initial publication before Dependabot will propose it as an update. This transforms the attack timeline:
| Stage | Without Cooldown | With 7-Day Cooldown |
|---|---|---|
| Malicious package published | Day 0, 9:00 AM | Day 0, 9:00 AM |
| Dependabot detects update | Day 0, 2:00 PM | Day 7, 2:00 PM |
| Security community flags issue | Day 1-3 (typical) | Already flagged by Day 7 |
| Repository exposure risk | HIGH (hours) | LOW (vetting window) |
The 7-day window aligns with typical security research timelines: npm's security team, GitHub's advisory database, and community scanners usually identify malicious packages within 24-72 hours of publication. By day 7, malicious versions are typically yanked or flagged, and Dependabot will skip proposing them.
Why Both Ecosystems Needed the Fix
Both npm and github-actions ecosystems required identical cooldown configuration because:
- npm: Direct dependency supply chain for application code—malicious packages execute in production
- github-actions: Indirect supply chain compromise—malicious actions execute during CI/CD with repository secrets and write permissions
GitHub Actions supply chain attacks have become increasingly common, with attackers publishing actions that appear to provide useful functionality but exfiltrate GITHUB_TOKEN secrets or modify repository contents.
Prevention & Best Practices
Configuration Hardening
-
Mandatory cooldown for all ecosystems: Every
package-ecosystementry should have:
yaml cooldown: default-days: 7 # Minimum; consider 14-30 for critical systems -
Conservative schedule intervals: Consider
weeklyinstead ofdailyfor less critical dependencies, reducing the frequency of update proposals. -
Review requirements for Dependabot PRs: Never auto-merge Dependabot PRs. Require human review with specific security checks:
- Verify package publication date (should be >7 days ago with cooldown)
- Check npm/GitHub security advisories
- Review diff of actual changes
Detection Tools
- Semgrep: Use rule
package_managers.dependabot.dependabot-missing-cooldownin CI pipelines - GitHub Advanced Security: Enable dependency review to block PRs with known vulnerabilities
- npm audit: Run in CI to catch known vulnerabilities before deployment
Security Standards
- OWASP Software Component Verification Standard (SCVS): Controls for third-party component management
- SLSA (Supply-chain Levels for Software Artifacts): Framework for securing build pipelines
- CWE-1104: Use of Unmaintained Third Party Components
- CWE-829: Inclusion of Functionality from Untrusted Control Sphere
Key Takeaways
- Always configure
cooldown: default-days: 7in.github/dependabot.ymlfor everypackage-ecosystementry—this is not a default, it must be explicit - The
intervalschedule does not protect against zero-day packages—onlycooldowncreates the necessary publication-to-proposal delay - GitHub Actions ecosystems need the same protection as npm—compromised actions have privileged access to your build environment and secrets
- 7 days is the security community's minimum vetting window—shorter periods risk including packages before they're flagged; longer periods (14-30 days) add safety for critical systems
- Dependabot configuration is production security infrastructure—treat
.github/dependabot.ymlwith the same security rigor as application code
How Orbis AppSec Detected This
- Source: The
.github/dependabot.ymlconfiguration file, specifically thepackage-ecosystementries at lines 3 and 9 - Sink: The absence of
cooldownconfiguration allowing immediate proposal of newly published package versions - Missing control: No
default-dayswaiting period to validate package stability and legitimacy before automated update proposals - CWE: CWE-1104 (Use of Unmaintained Third Party Components) and CWE-829 (Inclusion of Functionality from Untrusted Control Sphere)
- Fix: Added
cooldown: default-days: 7to bothnpmandgithub-actionspackage ecosystem entries, enforcing a mandatory 7-day embargo on new package versions
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 requires defense in depth at every automation touchpoint. The missing cooldown configuration in .github/dependabot.yml represented a single point of failure where legitimate automation could become an attack vector. By adding cooldown: default-days: 7 to both npm and GitHub Actions ecosystems, we've inserted a critical security buffer that aligns automated dependency management with community vetting timelines.
For development teams, this fix serves as a reminder: your CI/CD configuration files are as security-critical as your application code. Review your Dependabot configurations today, and ensure every package-ecosystem has an appropriate cooldown period. The 7-day wait could be the difference between blocking a supply chain attack and becoming its next victim.
References
- CWE-1104: Use of Unmaintained Third Party Components — https://cwe.mitre.org/data/definitions/1104.html
- CWE-829: Inclusion of Functionality from Untrusted Control Sphere — https://cwe.mitre.org/data/definitions/829.html
- GitHub Dependabot Cooldown Documentation — https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#cooldown
- Semgrep Rule: dependabot-missing-cooldown — https://semgrep.dev/r?q=package_managers.dependabot.dependabot-missing-cooldown
- OWASP SCVS (Software Component Verification Standard) — https://owasp.org/www-project-scvs/
- fix: this dependabot configuration does not set a co... in...