Introduction
In a Node.js library's repository, we discovered a high-severity supply chain configuration vulnerability at line 3 of .github/dependabot.yml. The file defined two package ecosystem entries—npm and github-actions—both configured to check for updates weekly with a limit of 10 open pull requests. However, neither entry included a cooldown block, meaning Dependabot would immediately propose updates to packages the moment they were published to npm or the GitHub Actions marketplace.
For a Node.js library, this is particularly dangerous: downstream consumers who depend on this package inherit whatever dependencies it pulls in. If a malicious actor publishes a compromised version of a transitive dependency and Dependabot immediately creates a PR that gets merged, every downstream project consuming this library becomes vulnerable.
The Vulnerability Explained
What Was Missing
Here's the original .github/dependabot.yml configuration:
version: 2
updates:
- package-ecosystem: npm
directory: /
schedule:
interval: weekly
open-pull-requests-limit: 10
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
Notice there's no cooldown configuration anywhere. This means that if a package publishes version 2.1.0 at 3:00 AM on a Tuesday, and Dependabot's weekly check runs at 3:01 AM, it will immediately create a pull request proposing the upgrade—before anyone in the security community has had a chance to analyze the new release.
Why This Matters
Supply chain attacks against npm packages are not theoretical. Real-world incidents include:
event-stream(2018): A malicious maintainer published a compromised version that stole cryptocurrency wallets. It took days before the community noticed.ua-parser-js(2021): A hijacked package pushed cryptominers to millions of downstream projects.colorsandfaker(2022): Maintainer-initiated sabotage that broke thousands of projects.
In all these cases, a 7-day cooldown would have provided critical protection. The malicious versions were typically identified and reported within 24-72 hours—well within a 7-day buffer.
Attack Scenario Specific to This Configuration
Consider this attack flow against this Node.js library:
- An attacker compromises a maintainer account for one of this library's npm dependencies
- They publish a new patch version (e.g.,
lodash@4.17.22) containing obfuscated malware - Dependabot immediately detects the new version during its weekly scan
- Without a cooldown, Dependabot creates a PR proposing the upgrade
- A maintainer, seeing a routine patch bump from a trusted package, merges it
- The compromised dependency is now part of the library
- All downstream consumers who run
npm installon projects depending on this library receive the malicious code
The same attack vector applies to the github-actions ecosystem entry—a compromised GitHub Action could exfiltrate secrets from CI/CD pipelines.
The Fix
The fix adds a cooldown block with default-days: 7 to both package ecosystem entries in .github/dependabot.yml:
Before (Vulnerable)
version: 2
updates:
- package-ecosystem: npm
directory: /
schedule:
interval: weekly
open-pull-requests-limit: 10
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
After (Fixed)
version: 2
updates:
- package-ecosystem: npm
directory: /
schedule:
interval: weekly
open-pull-requests-limit: 10
cooldown:
default-days: 7
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
cooldown:
default-days: 7
How the Fix Works
The cooldown configuration tells Dependabot: "After a new version of any package is published, wait at least 7 days before creating a pull request to update to that version." This provides a critical safety window:
- Community vetting: 7 days gives security researchers, automated scanners, and the open-source community time to analyze new releases
- npm advisory propagation: GitHub's advisory database and npm's security team typically flag compromised packages within 1-3 days
- Stability verification: Even non-malicious releases sometimes have critical bugs that are caught within the first week
Both ecosystem entries needed the fix because:
- npm: Protects against compromised JavaScript packages that would be bundled into the library
- github-actions: Protects against compromised CI/CD actions that could steal repository secrets, inject code, or tamper with build artifacts
Prevention & Best Practices
1. Always Configure Cooldown Periods
Every dependabot.yml should include cooldown periods. For high-security environments, consider longer periods:
cooldown:
default-days: 7
# Optional: longer cooldowns for specific dependency groups
2. Combine Cooldown with Other Defenses
A cooldown is one layer of defense. Also consider:
- Lock files: Always commit
package-lock.jsonto pin exact versions - npm audit: Run
npm auditin CI pipelines to catch known vulnerabilities - Dependency review: Use GitHub's dependency review action to block PRs introducing known-vulnerable packages
- Signed packages: Prefer packages with provenance attestations (npm's
--provenanceflag)
3. Audit Your Dependabot Configuration Regularly
Use static analysis tools like Semgrep to scan your .github/dependabot.yml for misconfigurations:
semgrep --config "p/supply-chain" .github/
4. Restrict Auto-Merge for Dependency Updates
Never auto-merge Dependabot PRs without additional checks. Combine cooldown with:
- Required CI passing
- Required security scan passing
- Manual approval for major version bumps
5. Monitor for Typosquatting
The cooldown protects against compromised legitimate packages, but also helps with typosquatting attacks where similarly-named malicious packages are published.
Key Takeaways
- The
cooldownblock independabot.ymlis not optional for production Node.js libraries—it's a critical supply chain defense that should be present in every ecosystem entry. - Both
npmandgithub-actionsecosystems needed the fix because supply chain attacks target both runtime dependencies and CI/CD infrastructure. - 7 days is the recommended minimum cooldown because most malicious package publications are detected and reported within 1-3 days by the security community.
- This Node.js library's downstream consumers were at elevated risk because a compromised transitive dependency would propagate to every project that depends on this library.
- Static analysis with Semgrep can detect configuration-level supply chain risks that traditional code scanners miss—security extends beyond just source code.
How Orbis AppSec Detected This
- Source: Newly published package versions on the npm registry and GitHub Actions marketplace
- Sink:
.github/dependabot.ymlecosystem entries at lines 3 and 8, where Dependabot evaluates whether to propose updates - Missing control: No
cooldownblock to delay adoption of newly published package versions - CWE: CWE-829 (Inclusion of Functionality from Untrusted Control Sphere)
- Fix: Added
cooldown: default-days: 7to both thenpmandgithub-actionspackage ecosystem entries, ensuring a 7-day waiting period before Dependabot proposes updates to newly released 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 is one of the most critical challenges facing the Node.js ecosystem today. A missing cooldown configuration in Dependabot might seem like a minor oversight, but it removes a crucial time-based defense against malicious package publications. By adding a 7-day cooldown to both the npm and github-actions ecosystem entries in this library's .github/dependabot.yml, we've ensured that newly published packages must survive community scrutiny before being proposed as updates—protecting both this library and all its downstream consumers.
The lesson is clear: your dependency management configuration is part of your security posture. Treat .github/dependabot.yml with the same rigor you apply to your application code.