<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Wilson Santos</title>
    <description>The latest articles on DEV Community by Wilson Santos (@wilson-draugr).</description>
    <link>https://dev.to/wilson-draugr</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4145879%2F7b1b59ad-111c-426b-a7f7-1eab66b38621.jpg</url>
      <title>DEV Community: Wilson Santos</title>
      <link>https://dev.to/wilson-draugr</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/wilson-draugr"/>
    <language>en</language>
    <item>
      <title>What to fix first when everything is critical</title>
      <dc:creator>Wilson Santos</dc:creator>
      <pubDate>Thu, 01 Oct 2026 20:31:45 +0000</pubDate>
      <link>https://dev.to/wilson-draugr/what-to-fix-first-when-everything-is-critical-2fh0</link>
      <guid>https://dev.to/wilson-draugr/what-to-fix-first-when-everything-is-critical-2fh0</guid>
      <description>&lt;p&gt;Run any scanner across a real system and you will get the same shape of result, a wall of&lt;br&gt;
findings, most of them stamped "high" or "critical." Those labels come from&lt;br&gt;
&lt;strong&gt;&lt;a href="https://draugr.dev/learn/cve-cvss-and-severity/" rel="noopener noreferrer"&gt;CVSS&lt;/a&gt;&lt;/strong&gt;, the Common Vulnerability Scoring System, a 0 to 10 scale&lt;br&gt;
published with most vulnerabilities. The word is a band on that scale, and the bands are defined by&lt;br&gt;
FIRST in the &lt;a href="https://www.first.org/cvss/v3.1/specification-document" rel="noopener noreferrer"&gt;CVSS v3.1 specification&lt;/a&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;The label&lt;/th&gt;
&lt;th&gt;The score&lt;/th&gt;
&lt;th&gt;What it took to earn it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Critical&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;9.0 to 10.0&lt;/td&gt;
&lt;td&gt;reachable over a network, by somebody with no account, needing nothing from a user, and it takes confidentiality, integrity and availability together&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;High&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;7.0 to 8.9&lt;/td&gt;
&lt;td&gt;most of the above, with one condition attached. An account is needed, or the attack is not straightforward, or one of the three impacts is spared&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Medium&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;4.0 to 6.9&lt;/td&gt;
&lt;td&gt;several conditions at once, or a partial impact. The bulk of what a scanner returns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Low&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.1 to 3.9&lt;/td&gt;
&lt;td&gt;local access, or heavy prerequisites, or an impact that is real and narrow&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That is a useful thing to know and it is not a statement about you. The specification is explicit&lt;br&gt;
about it: a base score reflects severity &lt;em&gt;"assuming the reasonable worst case impact across&lt;br&gt;
deployed environments"&lt;/em&gt;. So &lt;code&gt;AV:N/PR:N&lt;/code&gt;, the pair that makes a 9.8, is a claim that &lt;em&gt;somebody's&lt;/em&gt;&lt;br&gt;
deployment exposes this to the internet without authentication. It is not a claim that yours does.&lt;/p&gt;

&lt;p&gt;So the score did its job: it told you how severe each issue is in the abstract. What it did not tell&lt;br&gt;
you is the only thing you need on Monday morning: &lt;strong&gt;which one do I fix first?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Severity is not priority. And the gap between them is where security programs quietly fail.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why severity can't rank your work
&lt;/h2&gt;

&lt;p&gt;CVSS scores a vulnerability in isolation, as if every place it appears were identical. But&lt;br&gt;
the same CVE is not the same risk everywhere:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;The same CVE, sitting on&lt;/th&gt;
&lt;th&gt;What it actually is&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;an internet-facing service with no auth&lt;/td&gt;
&lt;td&gt;a live attack path&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;an internal tool three network hops away, behind a policy&lt;/td&gt;
&lt;td&gt;a someday-maybe&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;the component that takes the platform with it when it falls over&lt;/td&gt;
&lt;td&gt;an emergency, whatever the score says&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Feed all of that into one severity number and you get the two failure modes every team knows:&lt;br&gt;
either you chase &lt;em&gt;everything&lt;/em&gt; marked critical and burn out, or you stop believing the labels&lt;br&gt;
and route around the gate. Both end in the same place, with the urgent thing sitting in a&lt;br&gt;
backlog next to a hundred things that look exactly as scary.&lt;/p&gt;
&lt;h2&gt;
  
  
  The two questions a scanner can't answer
&lt;/h2&gt;

&lt;p&gt;To rank findings you need two pieces of context that no scanner can compute, because they&lt;br&gt;
aren't properties of the code:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How exposed is it?&lt;/strong&gt; Reachable from the internet, or namespace-scoped behind a network policy? This is &lt;strong&gt;likelihood&lt;/strong&gt;, meaning how reachable the weakness is at all.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How much would it cost?&lt;/strong&gt; A platform-wide outage, or a dev tool nobody would notice for a week? This is &lt;strong&gt;impact&lt;/strong&gt;, meaning what it costs when it goes wrong.&lt;/p&gt;

&lt;p&gt;Real risk is the product of the two, layered on top of raw severity. A scanner sees none of it.&lt;/p&gt;
&lt;h2&gt;
  
  
  But your app description does
&lt;/h2&gt;

&lt;p&gt;You already know this context. You know which services face the world and&lt;br&gt;
which are buried. You know which ones are load-bearing. That knowledge is stable, small, and&lt;br&gt;
exactly the kind of thing &lt;a href="https://draugr.dev/blog/describe-your-app-not-your-scanners/" rel="noopener noreferrer"&gt;Draugr already captures&lt;/a&gt;&lt;br&gt;
in the app descriptor.&lt;/p&gt;

&lt;p&gt;So it becomes two more attributes on a component you already describe, its &lt;strong&gt;exposure&lt;/strong&gt; and its&lt;br&gt;
&lt;strong&gt;business criticality&lt;/strong&gt;, and prioritization falls out of the description you wrote once.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ingress-gateway&lt;/span&gt;
    &lt;span class="na"&gt;exposure&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;public&lt;/span&gt;          &lt;span class="c1"&gt;# reachable from the internet&lt;/span&gt;
    &lt;span class="na"&gt;criticality&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;critical&lt;/span&gt;     &lt;span class="c1"&gt;# failure = platform-wide outage&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dev-dashboard&lt;/span&gt;
    &lt;span class="na"&gt;exposure&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;restricted&lt;/span&gt;      &lt;span class="c1"&gt;# internal, network-scoped&lt;/span&gt;
    &lt;span class="na"&gt;criticality&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;supporting&lt;/span&gt;   &lt;span class="c1"&gt;# nobody pages at 3am for this&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhweb4r6ahx4ngu7xtnl1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhweb4r6ahx4ngu7xtnl1.png" alt=" " width="799" height="313"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Same finding, same severity, two answers, because the components differ.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now the &lt;em&gt;same&lt;/em&gt; CVE resolves two different ways, so on the gateway it is fix-now and top of the list.&lt;br&gt;
On the dashboard it is track-and-move-on. Severity was identical and &lt;strong&gt;priority was not&lt;/strong&gt;, because&lt;br&gt;
&lt;a href="https://draugr.dev/learn/vulnerability-prioritization/" rel="noopener noreferrer"&gt;priority&lt;/a&gt; combines the finding's severity with the&lt;br&gt;
component's exposure and criticality into a single, ordered answer.&lt;/p&gt;
&lt;h2&gt;
  
  
  The third input, whether anyone is exploiting it
&lt;/h2&gt;

&lt;p&gt;Exposure and criticality describe your side. There's one more signal, and it comes from the&lt;br&gt;
world: &lt;strong&gt;exploitability&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A CVE on &lt;a href="https://draugr.dev/learn/epss-and-kev/" rel="noopener noreferrer"&gt;CISA's KEV catalog&lt;/a&gt; is &lt;em&gt;known to be exploited in the wild&lt;/em&gt;, not&lt;br&gt;
theoretically exploitable, and used against real systems. That escalates a finding whatever&lt;br&gt;
its CVSS score says, because a modest score being exploited today outranks a 9.8 nobody has ever&lt;br&gt;
weaponized. A high &lt;a href="https://draugr.dev/learn/epss-and-kev/" rel="noopener noreferrer"&gt;EPSS&lt;/a&gt; probability, the likelihood a CVE gets exploited&lt;br&gt;
in the next thirty days, bumps a finding up a band on the same logic.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcl2tjwu445rm02jp9zqf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcl2tjwu445rm02jp9zqf.png" alt=" " width="800" height="339"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The severity did not change and neither did the code. What changed is that one of them is being used, which is a fact about the world rather than about your repository, and it is the input almost nobody feeds in.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Both are opt-in and read from feeds you provide, so the ranking stays reproducible, because the same&lt;br&gt;
inputs give the same order, and you can point at where each escalation came from.&lt;/p&gt;
&lt;h2&gt;
  
  
  An order is still a list, until it names the work
&lt;/h2&gt;

&lt;p&gt;Ranking gets the right thing to the top and shortens nothing: four hundred findings ranked are&lt;br&gt;
still four hundred rows, and the first twelve are often one library. So the last step groups them&lt;br&gt;
by the thing that fixes them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;draugr scan &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--view&lt;/span&gt; actions
&lt;span class="go"&gt;
WHAT TO DO  10 actions clear 508 findings
  P1  Update python:3.8-slim
      control images · 465 findings · upstream · CVE-2026-42010 +464
  P1  Upgrade jquery 1.8.3
      control sca · 16 findings · web/package-lock.json:10 · and 2 more · CVE-2020-11023 +15
  P1  Upgrade Jinja2 2.10
      control sca · 6 findings · app/requirements.txt:5 · CVE-2019-10906 +5
  ⋯
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the demo project, which carries 1,091 findings. Ten actions clear 508 of them, and the&lt;br&gt;
first row is one base image carrying 465 on its own.&lt;/p&gt;

&lt;p&gt;A row is a &lt;strong&gt;remediation&lt;/strong&gt;, not a finding. Six vulnerabilities in one library are one upgrade; the&lt;br&gt;
same misconfiguration in three Dockerfiles is one habit. Listing those separately makes the&lt;br&gt;
repetitive work crowd out everything else, which is how a ranked list still ends up unread.&lt;/p&gt;

&lt;p&gt;Actions are ordered by &lt;strong&gt;the worst thing each one clears&lt;/strong&gt;, and only then by how many. An action&lt;br&gt;
clearing a single P1 outranks one clearing forty P4s, because volume is not a reason to do&lt;br&gt;
something first and a P1 is not something to trade away for a bigger number.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;upstream&lt;/code&gt; on that first row means the team does not build that image, so the action is to take a&lt;br&gt;
newer one rather than to upgrade a package nobody there can reach. Advice you cannot act on, at the&lt;br&gt;
top of a list called &lt;em&gt;fix first&lt;/em&gt;, teaches people the list is not worth reading, and that is a fact&lt;br&gt;
about a contract rather than something a scanner can see. It comes from the descriptor, like&lt;br&gt;
everything else here.&lt;/p&gt;

&lt;p&gt;Grouping is opt-in while that annotation spreads: &lt;code&gt;--view actions&lt;/code&gt; turns it on, and the default&lt;br&gt;
still lists one finding per row. The report files always carry findings separately either way, so&lt;br&gt;
an auditor reading the SARIF sees one record per finding whichever way the console was asked to&lt;br&gt;
show them.&lt;/p&gt;

&lt;h2&gt;
  
  
  What that changes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  For a developer
&lt;/h3&gt;

&lt;p&gt;The output stops being a 400-row dashboard and becomes a short list: &lt;em&gt;these three, in this order, today.&lt;/em&gt; Clear action, not triage archeology.&lt;/p&gt;

&lt;h3&gt;
  
  
  For the business
&lt;/h3&gt;

&lt;p&gt;Consistent and defensible, because the same rules apply to every service. "What is our real exposure right now?" has an answer, and the urgent gets a faster response because it is no longer buried under look-alikes.&lt;/p&gt;

&lt;h3&gt;
  
  
  For your coding assistant
&lt;/h3&gt;

&lt;p&gt;The difference between a list and an order. Point one &lt;a href="https://draugr.dev/blog/your-assistant-is-already-answering/" rel="noopener noreferrer"&gt;at Draugr&lt;/a&gt; and it answers from the same ranking your pipeline uses. A scanner can hand it a pile of findings; only your description says which one to fix.&lt;/p&gt;

&lt;p&gt;This is what Draugr does. Not another dashboard that shows you &lt;em&gt;more&lt;/em&gt;, but a gate that tells you&lt;br&gt;
&lt;em&gt;less&lt;/em&gt;, being the few things that matter, ranked by your own context. Describe your app, and&lt;br&gt;
the description doesn't just decide which scanners run. It decides what you fix first.&lt;/p&gt;

</description>
      <category>security</category>
      <category>devsecops</category>
      <category>appsec</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
