What to fix first: from findings to changes
On this page
In plain terms
A fix list is a scan's findings rewritten as the changes that clear them, one row per change. Each row names the change, such as upgrading a library, editing a line of code, changing a setting or rotating a password, and counts the findings it clears. Each finding already carries a priority band, P1 for the most urgent down to P4, set from its severity and from what the descriptor, the committed file that declares a project's components, says about where the component runs and how much depends on it.
Why it matters
One change usually clears many findings. A library with eight known vulnerabilities takes one upgrade, and an old base image, the operating system layer a container is built on, can carry five hundred findings that moving to one newer image clears. Listed one finding per row, that image fills the first page of the report, and a reader cannot tell whether they are looking at five hundred problems or one.
The changes also belong to different people. A developer edits code, a platform engineer changes a cluster setting, and a team using an image somebody else publishes cannot upgrade a package inside it, only move to a newer image. A single list mixing all of these leaves each reader to work out which rows are theirs, and a row nobody reading it can act on teaches them to stop reading.
A reader follows a list when they can check why each row sits where it does, which takes an order built from values the report records and anyone can compare.
How it works
Findings become changes
Each row groups the findings that one change clears:
| Findings from | Grouped by | The change |
|---|---|---|
| a dependency scan (SCA) | package and installed version, in one component | upgrade to the release that fixes all of them |
| an image somebody else publishes | the image | move to a newer image |
| code analysis (SAST) | file and line | change that line |
| infrastructure code | rule | apply one fix across the files it flags |
| secret scanning | rule | remove the credential and rotate it |
Grouping stops where the change stops being one change. Twelve failed checks against one cluster are twelve settings to change, and a rule that flags ten lines of code is ten edits.
Changes are sorted by who makes them
| List | What it holds |
|---|---|
| Bump a dependency | an upgrade to the release that fixes a dependency, in a repository or an image you build, or a move of an image or repository somebody else publishes when any of its findings has a fix published |
| Change the code | a change to the application's code or its server's configuration |
| Change the infrastructure | a change to infrastructure code or a live setting |
| Rotate a credential | a committed secret to remove and then rotate |
| Wait for a release | a fix nobody has published yet: a package with no fixed release, or an image or repository none of whose findings has one |
| Decide | a decision rather than a change: a license to accept or replace, an operating system past end of service life |
The lists always appear in this order, and the order says nothing about urgency. Each list is ordered on its own, so the first row of Change the code is the most urgent change to code even when an image in Bump a dependency clears hundreds of findings. Every change is in exactly one list.
Each list is ordered key by key
To order two rows, compare them on these keys from the top, and the first key where they differ decides.
| Key | Which row comes first | |
|---|---|---|
| 1 | Priority | the one clearing the more urgent band, P1 to P4. A change clearing one P1 comes before one clearing forty P4s |
| 2 | Exploitation | the one clearing a flaw on CISA's Known Exploited Vulnerabilities (KEV) catalog, then the one clearing a flaw whose EPSS score, an estimate of how likely it is to be exploited in the next 30 days, is above the descriptor's threshold. Both apply where config.exploitability turns them on |
| 3 | Severity | the one clearing the higher severity, after KEV or EPSS raised it or reachability lowered it |
| 4 | Count | the one clearing more findings |
| 5 | Upgrade policy | the step within the component's upgrade policy. A component that takes only minor upgrades gets two rows for a fix that needs a major one, the minor step and the step past it marked major · beyond policy minor. The step within the policy comes first because the other presumes it, and both rank together, by the more urgent of the two, so they sit side by side |
Two rows that match on every key keep the order of the findings list, which ends on component, repository, location and rule, so the same scan produces the same list every time.
Count is near the end because it measures how a scanner counts more than how much a change matters. A scanner that reports every advisory against every package counts an old image in the hundreds, and ranked on volume that image would sit above a single flaw attackers are using today.
Where each key is recorded
The band, the severity and whatever changed the severity are recorded on each finding, in the
report and the SARIF file a scan writes, and the upgrade policy is fixes.upgrade in the
descriptor. A KEV escalation names the feed and the date its copy was fetched:
"escalation": {
"from": "medium",
"to": "critical",
"signal": "kev",
"detail": "on KEV",
"asOf": "2026-10-25",
"alsoMatched": [
{ "signal": "epss", "detail": "EPSS 0.85", "asOf": "2026-10-25" }
]
}
To check why one row sits above another, compare those values on the findings each row clears. Every key is on a finding, in the descriptor or a count of findings, so the order can be rebuilt by hand.
What the list cannot know
Whether a service faces the internet, and what stops when it fails. Priority folds in each component's declared exposure and criticality, because no scanner can see either. A component declared internal that is in fact public ranks too low. The declaration lives in the descriptor, a file the team reviews like any other change, which is where a wrong one gets noticed and fixed.
Whether an image or a cluster is yours. builtBy: upstream on an image marks one somebody else
publishes, which turns its findings into one move to a newer image instead of upgrades nobody can
make. operatedBy: provider on a cluster marks one a cloud provider runs, which keeps findings
about the parts the provider operates counted in the report and out of the list of work.
How Draugr fits
draugr scan --view actions prints the fix list, one list per kind of work, with the first three
rows of each. Without --view actions, a scan lists one finding per row.
$ draugr scan . --view actions
WHAT TO DO 50 actions clear 1154 findings
Bump a dependency 12 actions clear 559 findings
P1 Upgrade jquery 1.8.3 → 1.12.2
component storefront · control sca · 4 findings · web/package-lock.json:12 · NSWG-ECO-329 +3
P1 Upgrade jquery 1.12.2 → 3.5.0 major · beyond policy minor
component storefront · control sca · 5 findings · web/package-lock.json:12 · and 1 more
P1 Upgrade jquery 1.8.3 → 3.5.0 major · beyond policy patch
component api · control sca · 7 findings · app/static/js/jquery.min.js vendored · CVE-2020-11023 +6
… and 9 actions not listed
Change the code 14 actions clear 23 findings
P1 Fix “Found user-controlled data used in a system call”
Semgrep: dangerous-system-call · Bandit: B605
component api · control sast · 2 findings · app/app.py:16
⋯That is the demo project. In the same list, the row for the python:3.8-slim image clears 520
findings and ranks below these three. All four are P1, and the jquery upgrades to 3.5.0 clear
CVE-2020-11023, which is on KEV, while none of the image's findings is. The first row is the step
within the storefront's minor policy, ranked with the step after it. vendored marks a copy of a library committed to the tree, which bumping the lockfile leaves
as it was. On the code row, two scanners flag the same line under different rules, and one edit
clears both.
--top N shows the first N rows of each list and --top 0 shows every one. The
MCP server's fix_list tool hands an AI assistant the same
lists, and takes kind to return one. The report files keep every finding as its own record either
way, so an auditor reading the SARIF sees one per finding. What to fix
first in the docs has every grouping rule and key.
Keep learning
- Vulnerability prioritization, the band each row is ranked by
- EPSS & KEV, the exploitation key
- Container image scanning, where an image's findings come from
- Reachability, which lowers a finding nothing calls