The Dependabot alert badge just hit double digits. So — which do you fix first? This is where many teams freeze. The common reflex is "by descending severity (Critical/High)." It looks right, but it's the biggest trap: it gets the priority wrong. Severity only tells you "how much it hurts if it's exploited," and says nothing about "whether it will be exploited at all."
This article, a topic of the Dependabot production-operations guide, focuses on the ranking of "what to fix first." Enablement, SLA, and the operation of auto-triage itself are left to the alerts & security-updates guide; here we design triage along three axes — CVSS × EPSS × reachability — to cut alert fatigue and focus on the truly dangerous few.
Rules for this article: the EPSS/CVSS definitions follow FIRST's primary sources, and Dependabot's behavior follows the GitHub official documentation (as of July 2026). EPSS is a "probability," not a "certain prophecy." Always confirm the latest numbers and interpret them in your context (public vs. internal, regulated industry).
1. Why sorting by severity (CVSS) alone gets the priority wrong
CVSS (Common Vulnerability Scoring System) is a static score that expresses a vulnerability's severity — the size of the impact — from 0 to 10. The GitHub Advisory Database ingests the CVSS v4.0 / v3.1 / v3.0 assigned by the maintainer and shows it as severity (Critical/High/Medium/Low) on Dependabot alerts.
CVSS is an excellent measure of "how much it hurts if exploited," but it's missing something decisive — "will it actually be exploited?" The world is full of CVSS 9.x vulnerabilities that are almost never attacked in reality, and conversely medium-CVSS ones for which attacks are being observed. Sort by descending severity and clear from the top, and you melt effort on Criticals that are rarely attacked while deferring the ones under active attack — this is the "severity-sort trap."
GitHub's analogy makes it clear: CVSS is "how bad the damage if someone broke into your house," and EPSS is "how likely someone is actually going to try." You can't paint the full picture of risk without both.
2. EPSS: measuring the "probability" of being attacked
EPSS (Exploit Prediction Scoring System) is a data-driven machine-learning model published by FIRST that estimates, from 0 to 1 (0–100%), the probability that "a published CVE will be exploited in the wild within the next 30 days."
The key points (per FIRST's official docs):
- Meaning: the higher the score, the higher the probability the vulnerability will actually be attacked in the near future.
- Update frequency: every CVE is updated every day and published via CSV / API.
- Percentile: beyond the absolute probability, it also provides a "relative position among all CVEs."
- Difference from CVSS: where CVSS measures subjective severity, EPSS measures the "likelihood of exploitation" with empirical signals from observed exploitation. Severity and likelihood are different things.
In other words, EPSS answers, with a probability, the question CVSS can't: "is this vulnerability actually going to be targeted this month?" The two aren't competitors — they're complements.
3. Handle it with a CVSS × EPSS matrix
The implementation of ranking becomes unambiguous once you drop it into a two-axis matrix.
| High EPSS (attacks are coming) | Low EPSS (no exploitation signs yet) | |
|---|---|---|
| High CVSS (large impact) | Top priority: patch & deploy immediately | Handle on a plan (monitor, roll into the next scheduled update) |
| Low CVSS (small impact) | Monitor / mitigate (often attacked, but limited impact) | Defer (mostly noise; an auto-triage dismiss candidate) |
GitHub itself illustrates this thinking with an example: a "EPSS 85% / CVSS 9.8" vulnerability should "almost always" take priority over an "EPSS 0.5% / CVSS 9.0" one. Both are Critical by severity, but the probability of being attacked differs by orders of magnitude. Look only at severity and these two line up as "the same Critical."
Why focusing on the few works: EPSS research reports that prioritizing by EPSS lets you cover the large majority of the vulnerabilities actually exploited while addressing only a small fraction of them. "Fix the dangerous few for certain" rather than "fix everything" is far more cost-effective against finite engineering time — this is the economic basis of EPSS-based triage.
4. The third axis: reachability and dependency scope
CVSS × EPSS measures the "danger in general." But a final question remains: "can that vulnerability actually be reached in our app?" This is reachability.
An important fact here: Dependabot detects whether a vulnerable dependency "exists" in the dependency graph. It does not determine whether your code actually calls that vulnerable function. A vulnerability in a code path that's present as a dependency but never actually reached can remain a theoretical risk.
Rigorous reachability analysis is the domain of other tools, but in practice you first use dependency scope (dev / prod) as a proxy.
- Production dependencies (production scope): can process user input at runtime. Treat as high reachability.
- Development dependencies (development scope): only at build/test time. Less exposed to the production attack surface, so often low reachability (protecting the CI environment itself is a separate concern).
So the final priority is decided on three axes — CVSS (impact) × EPSS (probability) × reachability (does it run in production?). "Production dependency × high CVSS × high EPSS" is top priority; "dev dependency × low CVSS × low EPSS" is an auto-triage auto-dismiss.
5. Putting it into practice on GitHub
5.1 Sort alerts by EPSS
GitHub has shown EPSS scores on Dependabot alerts since February 2025 (GitHub Enterprise Server 3.17+). EPSS is synced daily from FIRST. Sort the alert list by descending EPSS and you pick up "the vulnerabilities under active attack" first. Combine it with the severity filter to gather Critical/High and high EPSS at the top — that's the basic move.
5.2 Cut noise "before notification" with auto-triage rules
auto-triage rules match alerts on metadata like severity, EPSS, scope, package name, CVE, ecosystem, and manifest location, and automatically dismiss / snooze them before the notification fires. Being able to use EPSS as a condition is powerful — you can mechanize policies like:
- "Auto-dismiss alerts that are dev scope and low EPSS" — don't even notify for things with low production reachability and low attack probability.
- "Always keep high EPSS regardless of severity" — never drop the high-probability ones.
Because rules apply before notification, you achieve "don't raise it in the first place" rather than "filter it later." Limit auto-dismiss to what you can argue has no production impact, and keep the decision in the log.
5.3 Inventory the "unaddressed danger" with the REST API
To keep it running you need measurement. Dependabot alerts can be fetched via the REST API, so dashboard open × Critical/High and detect SLA breaches early.
# Extract only unaddressed Critical / High alerts (starting point for inventory & observability)
gh api \
-H "Accept: application/vnd.github+json" \
"/repos/{owner}/{repo}/dependabot/alerts?state=open&severity=critical,high" \
--jq '.[] | {number, severity: .security_advisory.severity, package: .dependency.package.name, ghsa: .security_advisory.ghsa_id}'
For an organization-wide view, use /orgs/{org}/dependabot/alerts and decide the human review order by descending EPSS. Being able to see at a glance whether unaddressed high-EPSS items are piling up is the last line of defense against a hollowed-out process. For designing the SLA itself, head to the alerts & security-updates guide.
6. Write down the prioritization policy
Triage runs on a written policy, not "gut feeling in the moment." If you're going to claim world-class, put these into words and share them across the team.
- The ranking formula: priority by production reachability × EPSS × CVSS (e.g., production × EPSS≥high × Critical at the very top).
- The auto-dismiss boundary: which scope / EPSS bands you drop via auto-triage, and the rationale.
- Handling exceptions: how you get past a high-EPSS vuln with no fix yet — mitigation (block the reachable path, disable the feature, WAF) or migrating to an alternative library.
- Review cadence: EPSS moves daily. What was "low" yesterday can be "high" today, so keep monitoring.
Triage means leaving the decision on record, not "leave it because it can't be fixed." Design ranking (this article) and "by when" — the SLA and automation (production-operations guide / alerts & security-updates guide) — as separate roles.
7. Avoid the common misconceptions
- "CVSS = risk" is false. CVSS is just the one axis of impact. Risk ≒ impact × probability × reachability.
- EPSS is a "probability," not a "prophecy." An attack may not come even at EPSS 90%, and a low EPSS can suddenly spike (which is why it's updated daily). Treat it as a probability and monitor continuously.
- Dependabot is SCA (known vulnerabilities in dependencies). Vulnerabilities in your own code (SQLi/XSS/SSRF/broken authorization) are the domain of SAST/DAST, a different layer from the EPSS/CVSS discussion. The full picture is in the web-app vulnerability-assessment guide.
Stop "top-down by descending severity," and focus on the few that are under attack, cause large damage, and run in production. That is, right now, the most cost-effective triage design for reducing the real supply-chain risk in the least time with finite effort.