Priority Board

Priority Board

A finished scan hands you hundreds of findings and no order to work them in. A malicious dependency sits in the same flat list as a missing DMARC record. The Priority Board scores every finding out of 100 (how likely it is to be real, how likely it is to be exploited, how bad that would be, and how reachable it is) and puts it in one of four tiers: Act now, Act soon, Plan, Track. Mute then lets you take a finding out of the picture entirely once you have decided it is not worth looking at.

The two halves are deliberately separate. The ranking is computed for you. Muting is a decision by you.

The ranking is done in code, not by an AI guessing. A model is used at one step, and only to check the findings that already rose to the top against their own evidence. Run it with no model configured and you still get a correct, complete ranking.


Table of Contents


The mental model (read this first)

  1. A rank orders a finding. It never hides one. Every finding gets a 0-100 score, the four factors behind it, the facts each factor came from, and (for the ones the AI reviewed) a verdict and the exact evidence it quoted. Everything stays visible.
  2. Muting is the only thing that hides. It is a human action, one click plus a confirm, and always reversible.
  3. A muted finding is invisible to the AI agent. Not de-prioritised, not filtered in the UI: genuinely unreachable. No question you can ask the agent will surface it.

That third point is the one worth internalising, and the "What muted actually means" section explains why it is stronger than it sounds.


What a triage run actually does

One run, five steps, in this order. Steps 1 to 4 happen entirely in memory; step 5 is the only one that writes anything.

StepWhat happensAI?
1. ScoreEvery open finding is read out of the graph with the project's facts (which hosts are live, which ports an active scan found, which packages are actually served, what the agent proved) and scored 0-100.No
2. GroupFindings that share one fix become one group: the same CVE on three hosts, or every advisory on one package.No
3. ReviewThe highest-ranked findings whose evidence can be judged are sent to the model in batches, with the request, the response, the file path and the validation result. It corrects the factors; it never produces a score.Yes
4. Fix itemsOne remediation per group, in the board's order, written into CypherFix.Partly
5. PublishThe whole result is written at once.No

Because nothing is written before step 5, a run you Stop, or one that is refused, leaves the previous ranking exactly as it was.

A real run on a 536-finding project, for scale: scored in about a second, 97 groups, 150 findings reviewed in 13 model calls, the whole thing in 9 minutes, producing 88 fix items.

What the AI is not allowed to do: it never sets a score, never mutes anything, never overrules your verdict, and never talks down a finding something proved. It has no tools bound at all, so an instruction hidden in scanner output has nothing to reach for.


How the ranking works

For every open finding, RedAmon estimates four things, each between 0 and 1:

FactorThe question it answersWhere it comes from
RealHow likely is this finding to be true?How it was detected: an exploit that ran, a matcher that captured proof, a version guess from a banner
ExploitIf it is real, how likely is it to be exploited?The strongest signal available: CISA KEV, EPSS, a public proof of concept, a usable credential, the CVSS exploitability metrics
ImpactHow bad would that be?The CVSS impact metrics, else the severity, else what kind of thing it is
ReachHow does an attacker get to it?A live endpoint, an open port an active scan found, a package actually served, a login wall, a local-only vector

Those four are multiplied, not added:

risk  = real x exploit x impact x reach
score = 25 x tier + 25 x risk          ->  0 to 100

Multiplying is the whole point. Risk is likelihood times impact, so something harmless can never outrank something devastating just by being easy, and a finding nobody can reach cannot outrank one sitting on the open internet.

The four tiers

The score is not a band applied afterwards. Fixed rules put each finding in a tier from its facts, and the tier is built INTO the score, so a bigger number always means more urgent:

TierWhat it meansRule
Act nowProven, or known-exploited and reachableSomething demonstrated it; or it is in CISA KEV, confidently detected and reachable; or it is a credential that was tested and works
Act soonLikely real, likely exploited, real impact, reachableAll four factors above their thresholds
PlanCredible, with impact worth schedulingPlausibly real, with some impact
TrackEverything elseReal facts, but not where your time goes

On a row, the score reads as a sentence: real 95% · exploit 70% · impact 0.75 · reach 1.0. Every one of those numbers names the fact it came from, so you can disagree with a specific input rather than with the conclusion.

State comes before score

A finding that is fixed, gone or inactive leaves the ranking altogether rather than being demoted to a small number that still sorts above something real:

StateWhat it means
FixedThe scanner confirmed it is patched, or a completed scan no longer reports it
GoneThe host has no live endpoint and no open port left
InactiveA credential that was tested and does not work

They keep all their facts and come back to the ranked list if a later scan finds them again.

The four sections

The board is always in the same four sections: Ranked, Not triaged yet, Likely false positive and Resolved. Each is described, with every column and every value, under Reading the board.

Where the proof comes from

RedAmon reads its own agent's results back out of the graph: the exploit modules GVM executed, the attack-chain outcomes the agent recorded, validated credentials, and malicious packages OSV confirmed. A proven finding is always Act now, and the AI cannot talk it down.

The board learns from your Real and False positive clicks

A detector that is right everywhere is still wrong on somebody's estate. The GitHub secret hunt flags private IP addresses as secrets, which on a network full of internal ranges is a hundred rows of pure noise, all of them scoring exactly what they would score anywhere else. Muting them worked, and then the next scan brought them back.

So every Real / False positive click is counted against the detector that produced the finding, and the Real factor for that detector moves towards what you actually found:

What you have told itWhat happens to Real for that detector
Nothing yetThe detection rule alone decides, exactly as before
One or two clicksAlmost nothing. A single unlucky click cannot re-rank your board
Ten clicksAbout halfway between the rule and your verdicts
Thirty clicks, all noiseNear the bottom, but never off

The detector is the rule that fired, not the finding: a nuclei template, a TruffleHog detector, a GVM test. So marking one tech-detect row false teaches it about the next tech-detect row and about nothing else. Advisories are the exception and deliberately learn per source rather than per CVE, because a verdict on one CVE says nothing about another.

Four things it will not do:

  • It never crosses users. Your clicks change your board. They are never pooled with anyone else's, on any plan.
  • It never silences a detector. Real is floored at 0.1. A detector you can no longer see is one you can never discover was right after all.
  • It never talks down a proven finding. An exploit ran. That is the same rule the AI review obeys.
  • It never hides why. Hover the factor line and it tells you: real 34%; detected by github_hunt; you judged 2 of 30 of these real.

What the AI actually does

It does not produce a score, a severity or a priority. Those come from the rules above.

Its job is the one thing rules cannot do: read the evidence a scanner captured (the request and the response, the file path, the validation result) and say whether the four factors match it. A nuclei "exposed .env" whose stored response is the site's own homepage is a false positive, and nothing about the graph's shape reveals that. The response body does.

Everything it says is checked in code before it counts:

  • Every quote must really appear in the evidence it was sent. A correction it cannot point at becomes "no change". This is the main defence against an invented reason.
  • Saying nothing costs nothing. "Unclear" with no disputes changes nothing at all, so an unsure model is never pushed towards a guess.
  • It can only correct named things. A verdict, an impact multiplier between 0.5 and 1.5, and one of eight named facts it can dispute. Nothing else.
  • The rules decide the outcome. After its corrections, the tier and the score are recomputed by the same rules as before, so it can never move a finding somewhere the facts do not support.
  • A proven finding cannot be talked down. Proof came from an exploit that ran; a sentence in a response body does not outweigh it.
  • Your own verdicts are never touched.

Findings it cannot usefully judge never reach it at all: a missing security header is a fact, and a dependency advisory's evidence is the advisory text rather than anything about your target. On a real project that is most of the graph, which is where the cost would otherwise go.


What "muted" actually means

When you mute a finding, RedAmon adds a marker to that node in the graph. From that moment:

WhereWhat you see
The graph viewGone
The AI agentGone, and it cannot be asked about
RedZone panelsGone
Insights & analyticsGone, including the node counts
ReportsGone
Recon DeltaNot reported as "resolved" (see below)
The Priority Board's Muted tableVisible: the only place it still is

The agent side is enforced at the single point every graph query the AI writes must pass through, the same place that stops one project reading another project's data. Every query the model emits gets the exclusion added automatically, whatever shape it is written in: labelled, unlabelled, or a bare "give me everything". The agent also has no vocabulary for mute at all: a query that even names the marker is refused outright rather than answered. So there is no phrasing, and no prompt, that gets a muted finding back out.

Why a mute is not reported as "fixed". Recon Delta compares two scans and lists what disappeared. A finding you muted disappeared without being fixed, so it is excluded from both sides of the comparison rather than being counted as resolved. Muting never makes your remediation numbers look better than they are.


Where to find it

The Priority Board tab sits on the Red Zone, next to Recon Delta and Scans. It lives with the graph it ranks, rather than as a separate page.

Its order and CypherFix's fix list are produced by the same run, so the two never disagree. The board tells you what to deal with first; CypherFix turns each group on it into a fix item, and can open the pull request. One button on either page runs both.


Reading the board

The four sections, always in this order

The server decides which section a finding is in, so the board cannot disagree with the ranking.

SectionWhat is in it
RankedOpen findings the last run scored, most urgent first. This is the working list.
Not triaged yetFound since the last run, or never triaged. They have no score yet. Run triage to rank them.
Likely false positive, check meThe AI or a person judged these not real. They are not muted and not deleted, and one click puts one back.
ResolvedFixed, gone, or a credential that no longer works. Kept, so they can come back if a scan finds them again.

Above the table, one chip per tier (Act now, Act soon, Plan, Track) with a count filters every section at once.

Every column

#ColumnWhat it holds
1#Rank within its section, so the first row of Ranked is 1. Not a stable id.
2FindingIts name, or its id when it has no name. A from <date> tag appears here when the row was scored by an older run than the newest one on the board, which is how you spot a finding a scan added after the last triage.
3TypeThe node label: Vulnerability, Secret, GithubSecret, GithubSensitiveFile, MultiscannerFinding, JsReconFinding, MalPackageFinding, ExploitGvm.
4ScoreThe 0-100 number, its tier chip, and the four factors underneath. Detailed below.
5VerdictWhat the AI concluded, or your own decision. Detailed below.
6SignalsThe named facts behind the factors, as chips. - when none applied.
7WhereThe host the model actually scored against. Falls back to the finding's location, then -.
8WhyThe one-sentence reason, plus a fix lever chip naming what would resolve it. - when the run wrote none.
9(actions)Real, False, Mute.

The Score column, in detail

A cell reads like this:

62.5  [Act soon]
real 95% · exploit 70% · impact 0.75 · reach 1.00

Where the number comes from. The four factors are multiplied, and the tier is added on top:

risk  = real × exploit × impact × reach          each 0 to 1, so risk is 0 to 1
score = 25 × tier_level + 25 × risk              T1=3  T2=2  T3=1  T4=0

Worked through for the cell above: 0.95 × 0.70 × 0.75 × 1.00 = 0.50 risk, and the tier is Act soon (level 2), so 25 × 2 + 25 × 0.50 = 62.5.

That gives each tier its own 25-point band (Track 0-25, Plan 25-50, Act soon 50-75, Act now 75-100), with the position inside the band set by the risk. So a bigger number is always more urgent, and sorting by it is exactly "tier first, then risk". One decimal is shown.

The multiplication is the part that matters: risk is likelihood times impact, so something harmless can never outrank something devastating just by being easy to exploit, and a finding nobody can reach cannot outrank one on the open internet. If any one factor is near zero, the score is near the bottom of its tier whatever the other three say.

  • The tier chip is one of four. Hover it and it names the rule that put the finding there, not a threshold:

    ChipTierThe rule that assigns it
    Act nowT1proven · KEV-listed, confidently detected and reachable · a validated credential
    Act soonT2likely real, likely exploited, real impact, reachable
    PlanT3credible, with impact worth planning for
    TrackT4nothing here has any impact · no rule placed this higher
  • The factor line is the four probabilities that were multiplied together. Hover it and each one names the fact it came from, for example real: detected by github_hunt; you judged 2 of 30 of these real.

    FactorShown asMeans
    reala percentageHow likely the finding is to be true, from how it was detected and from your own Real / False positive clicks on that detector
    exploita percentageHow likely it is to be exploited if it is real: the single strongest signal, never a sum
    impact0.00 to 1.00How bad it would be: the CVSS impact metrics, else the severity, else its class
    reach0.00 to 1.00How an attacker gets to it

    A row with no factors stored shows math only here instead, which is explained next.

Before and after a run: three things the Score cell can say

A finding is in one of three states, and the Score cell tells you which.

What you seeWhat it meansWhat produced it
-No score at all. Triage has never scored this finding.Nothing. There is no number to calculate yet
34.4 + tier + factor lineFully scored by the current modelThe last triage run, score model v3
540.0 + tier + math onlyA leftover from the old scorer. It has a number but no breakdownA run from before score model v3

Before the first run there is no score

This is worth being plain about: nothing computes a score in the background. A scan finds a finding and writes it to the graph, and that is all. Until you press Rank Findings, the finding has no score, no tier and no factors. It sits in Not triaged yet with a -.

There is no partial or provisional number. The board is ranked only by a run you asked for.

What "math only" actually means

math only is not a kind of score. It is the board telling you the breakdown is missing: this row has a number, but not the four factors that should explain it.

That happens for one reason: the row was scored by the old points formula, which RedAmon replaced. The old scorer added points per signal and stored a bare number. It never stored the factors, the tier, or a model version.

Those numbers are on a completely different scale and are not comparable to the new ones. In one real database, rows still carrying old scores ranged from -100 to 640, with dozens above 100, while every v3 score is between 0 and 100. A 540 next to a 34.4 does not mean it is fifteen times more urgent; it means the two were produced by two different systems.

Because the old rows carry no stored tier either, the chip beside them is a rough guess the interface makes from the number alone, not the rule-based tier the current model assigns.

Re-run triage and they are replaced. One run rewrites every finding in the project with a v3 score, a rule-assigned tier and the full factor line. math only is a sign the project is overdue a run, and nothing more.

The score before the AI, and the score after

Two numbers are stored per finding:

Stored asWhat it is
triage_math_scoreThe score from the rules alone, before the AI looked at anything
triage_priority_scoreThe final score, after the AI corrected the factors. This is what the board shows and sorts by

They are identical for every finding the AI did not review, which on a typical project is most of them. When they differ, it is because the AI disputed a factor against the evidence and the same rules were re-run on the corrected factors. The AI never edits a score directly: it can only move real, exploit, impact or reach, and the arithmetic is redone from those.

So the model with no key configured, and the model with a key, differ only in how good the four factors are. The formula on top of them never changes.

The Verdict column, in detail

ValueMeaning
RealThe AI checked the evidence and it supports the finding
DoubtfulThe evidence is weaker than the finding claims
Likely false positiveThe evidence contradicts it. The row moves to the third section
UnclearThe AI declined to judge. This deliberately changes nothing about the rank
Not reviewedOutside the review budget, or no model configured, or its evidence needed no second opinion. The maths still ranked it
You: RealYour decision. No run and no AI will ever change it
You: False positiveYour decision. The row moves to the third section, and it is not muted

Hover the chip to see which model reviewed it. Underneath, when the AI gave one, sits the exact quote it took from the evidence, in quotation marks. Every quote is verified to be a real substring of what the model was shown, so it cannot invent one.

The Signals column, in detail

ChipWhat it means
provenSomething demonstrated it: an exploit ran, a credential validated, or OSV lists the package as malicious
KEVThe CVE is in the CISA Known Exploited Vulnerabilities catalogue
EPSS 0.94The CVE's exploit-prediction score, 0 to 1
public PoCA public proof of concept exists
live endpointIts host answered an HTTP probe
hot hostThe agent already compromised that host
sensitive assetThe host exposes a database port, a login, an admin vhost, MCP or GraphQL
origin exposedIt sits behind a CDN whose origin is reachable directly
CVSS v3A CVSS vector was parsed, and which version it was (v2, v3, v4)
a class nameWhat kind of thing it is: dependency, credential, generic secret, exposure, misconfig, hardening, info disclosure, cdn bypass, identifier, rate limit, spoofing

The row actions

ButtonWhat it does
RealRecords your verdict. Triage never changes it again, and the AI cannot overrule it
FalseRecords it as a false positive. It moves to the third section. It is not muted and not deleted
MuteThe only action that hides anything. Confirm required. See below

Both verdict buttons also teach the board: each click is counted against the detector that produced the finding, and shifts the real factor for that detector on your future runs.

The Muted table

Collapsed by default, behind Show muted (n). It is the only place in the product where a muted finding is visible at all.

ColumnWhat it holds
FindingIts name
TypeIts node label
SeverityThe severity the scanner reported
MutedWhen it was muted
ByWho muted it
ReasonThe reason they typed

Each row has Restore, which brings it straight back into the ranking.


Running the Priority Board

One button, on the Priority Board and on CypherFix, runs one job. Its results become the board's order and the CypherFix fix list, so the two always agree.

Before it starts, a dialog tells you what this run will do with your project's own numbers in it: how many findings are in scope and how many are new, when the last run was and with which model, roughly how many AI calls it will cost, how many fix items are pending and how many someone is already working on.

  1. Score. Every finding, from the facts in the graph. No AI.
  2. Group. Findings that share a fix are grouped: one CVE on three hosts is one group, and every advisory on one package is one group.
  3. Review. The AI checks the evidence behind the findings it can judge.
  4. Fix items. One per group, in the same order as the board.
  5. Publish. Everything at once, at the end.

Nothing is written until the last step. Until then, the previous ranking is still what you see, so a run you stop, or one that is refused, has changed nothing at all.

The run is a background job: it outlives the tab that started it. Leave the page mid-run and it keeps going; come back and it re-attaches. Only Stop cancels it, and only one run per project at a time.

While it runs, version activation, project import and project delete wait for it. Scans do not: they can keep running, and any finding a scan changes mid-run is left for the next run rather than being published with facts that have since moved.

Which model runs it

The model set in Project Settings → CypherFix & Priority Board LLM Model, falling back to your Agent Behaviour model when that is empty. Priority Board: findings the AI reviews caps what a run costs; set it to 0 for a fully ranked, AI-free board. Findings whose evidence has not changed since the last review are reused and cost nothing.

Your override wins

Press Real or False positive on a finding and that verdict is yours. Later runs never overwrite it, and neither can the AI.

What they do keep updating are the facts and the four factors, because those are measurements. A finding you judged last month should not still be ranked on last month's graph: if the host has since gone away, or a CVE it carries has since entered CISA KEV, you want to know. Your decision about whether it is real stays exactly as you left it.

Mute, the one action that hides something, always survives a re-run.


Safety properties worth knowing

These are enforced in code, not by asking the model nicely:

  • A run cannot mute anything. There is no code path from a triage run to the mute label, and there never must be. Scanner output (response bodies, evidence strings, matched URLs) is attacker-influenced text, and the worst it can achieve is a visible, reversible verdict on the finding whose own evidence carried it.
  • The AI has no tools. The review and the fix-item calls bind none, so an injected instruction has nothing to reach for. It cannot query the graph, search the web, reach another project, or write anything but the handful of validated fields listed above.
  • A failed run leaves findings visible. If the model is unreachable, the ranking still publishes and the findings are marked "Not reviewed". The system fails towards showing you too much, never towards hiding something.
  • A stopped run changes nothing. Everything happens in memory until the last step, so stopping mid-run leaves the previous ranking exactly as it was.
  • A scan during a run cannot corrupt it. Any finding a scan changes while a run is working is skipped at publish time and picked up by the next run, rather than being written with facts that have since moved.
  • Only findings can be muted. Hosts, ports, domains, endpoints and certificates cannot: muting an IP would orphan the real findings attached to it.
  • Mute survives a re-scan, and so does everything else you decided. A scan no longer deletes its findings and re-creates them: it refreshes the ones it still reports and removes the ones it does not. A finding you muted or judged is never removed, even when the scanner stops reporting it: it moves to Resolved and says so. You do not re-mute the same noise after every scan, and a fix item never ends up pointing at a finding that no longer exists.
  • Unmute is lossless. Restoring gives you the finding back with every relationship and property intact.
  • Only the project owner can mute, or start a run. Enforced on every Priority Board endpoint, and re-checked when a run is authorised. Neither check can be relaxed by the log-only access mode that exists for other routes, because both change what the agent can see rather than what a page displays.

Scans and versions

Everything triage produces (the score, the tier, the factors, the AI's verdict, your Real / False positive decisions and the mute) is stored on the graph nodes themselves, not in a separate table. So it is versioned exactly like the rest of the graph, and it travels with a project export and comes back on import.

A version is a photograph, so it keeps whatever was true when it was taken

A scan version is a frozen copy of the graph at one moment. Whether it contains a ranking depends only on when it was made:

  • A version created or frozen after a triage run contains that run's scores.
  • A version snapshotted before any run has no scores at all. Activate it and its findings appear under Not triaged yet with a -.

This surprises people, so it is worth stating plainly: you do not triage a version. You triage the live graph. Any version made afterwards inherits that result, because the result was part of the graph it photographed. One run can therefore show up in several versions without you ever re-running it.

Switching versions is safe in both directions

Activating a version does three things in this order:

  1. Freezes the graph you are leaving into its own snapshot, so nothing is lost. If this fails, nothing is deleted and the switch is abandoned.
  2. Replaces the live graph with the chosen version's snapshot.
  3. Moves the pointer. The now-current version sheds its stored bytes, because it is the live graph.

Because of step 1, a round trip is lossless: switch away and back, and your ranking, your verdicts and your mutes are exactly as you left them.

A run in progress blocks activation. Triage reads the whole graph into memory and writes at the end, so switching underneath it would publish a ranking computed against a graph that no longer exists. Activation refuses while a run is live, and offers a Stop link.

The fix list does not switch with it

CypherFix's fix items are project-level, stored outside the graph, and activation deliberately leaves them alone, along with reports, scan output and captured traffic.

So after switching to a version with a different ranking, the board and the fix list can disagree: the board is truthful for the version you are now on, while the fix list still reflects whichever run produced it. Nothing reconciles that at switch time. The next triage run recomputes each item against the live graph, which is what restores agreement.

In practice: after activating a different version, re-run triage if you intend to work from the fix list.


FAQ

Does muting delete anything? No. The finding, its relationships and its history stay in the graph exactly as they were. Mute only changes who can see it.

Will the agent tell me a finding is muted? No. It cannot see muted findings and cannot query for them, so from the agent's point of view they do not exist. Look on the Priority Board tab instead.

Why is a header-hygiene finding at the very bottom? Because a missing header is a real fact with almost no impact and almost no way to exploit it, and the score multiplies those together. It is in Track, which is exactly right: worth knowing, not worth today.

If I mute something, does it vanish from a report I already generated? Reports are generated on demand, so a report you produce after muting will exclude it. Already-exported files are unchanged.

Can I mute a whole class of noise at once? Not yet: mute is per finding today. Findings that share a fix are grouped, and the board shows a group as one row, which is the groundwork for muting a group in one action.

Do I need an AI key to use it? No. The ranking, the grouping and the fix items are all produced in code. A key adds the evidence review, which mainly catches false positives, and better wording on the fix items.


See also