The session went well. Six people, three hours, a data flow diagram everyone agrees with, and a list of sixty-one threats — which is the point at which a lot of threat modelling programmes quietly die. Sixty-one is too many to fix, too many to argue about one at a time, and far too many to hand to a delivery team without an order attached. So the list becomes a spreadsheet, the spreadsheet becomes an attachment, and the next session never gets scheduled because nobody can point at what the last one changed.
The instinct at this point is to reach for a scoring model and grind through all sixty-one, producing a ranked list from 1 to 61. That is a lot of work to produce a number for item 47, which nobody will ever act on and which will be stale before they could. The list needs less arithmetic than it looks like it does, and more judgement — applied in a specific order, because doing it in the wrong order is what makes it feel impossible.
The short version: Collapse before you rank — half a long list is usually restatements and shared root causes, and the real number is nearer twenty. Rank what survives on two axes only, impact and exploitability, with a small fixed set of tie-breakers. Then band the result rather than ordering all of it: only the top band needs to be in the right sequence. Group that band by fix rather than by finding, because one architectural change routinely clears a dozen entries. Everything you are not doing gets accepted on the record, with a name and a date against it.
The list is shorter than it looks
A raw output of sixty-one is an artefact of how the session ran, not a measurement of how exposed you are. Brainstorming with STRIDE across every element on the diagram is deliberately generative: it is supposed to over-produce, because the cost of missing a threat is higher than the cost of writing down a duplicate. The tidying is a separate job, and it belongs before prioritisation rather than after, because ranking duplicates means ranking the same thing three times and then arguing about why it appears three times.
Do four passes over the raw list, in this order.
| Pass | What you are looking for | Typical effect |
|---|---|---|
| Merge restatements | The same threat written twice because two people said it about two elements — "token stolen from the mobile client" and "session hijacked on the API" are frequently one entry. | Removes 10–20% |
| Fold by root cause | Many findings, one cause. Eleven endpoints missing authorization checks is one architectural entry, not eleven, and it is fixed once. | The biggest reduction, and the most useful one |
| Strike the non-threats | Items that are actually missing requirements, ideas for features, or general anxieties with no attacker, asset, and action. Keep them — somewhere else. | Removes a handful, and improves the rest |
| Mark what is out of scope | Threats against systems you do not operate, handled by a platform contract, or belonging to a boundary another team owns. Record them as assumptions with an owner, not as your work. | Moves work rather than deleting it |
Sixty-one commonly comes out of this as thirty-something distinct threats resting on eight or nine underlying causes. That reframing is worth more than any scoring model, because "we have nine architectural problems" is a sentence an engineering lead can act on, and "we have sixty-one threats" is a sentence that makes them close the tab.
One warning about folding: fold by cause, never by component. Grouping everything that touches the payment service into "payments risks" hides that one of those items is a credential in a repository and another is a UI nicety. The test is whether a single fix closes every member of the group. If it does not, it is not one entry.
Rank on two axes, not five
With a workable number of entries, score them — and score them on the smallest set of dimensions that will still separate the top from the middle. Two do almost all the work:
- Impact. If this happens, what does it cost — in data, in money, in downtime, in regulatory exposure, in the conversation with your largest customer? Judge the realistic outcome, not the worst thing physically reachable from the finding.
- Exploitability. How much has to be true for this to work? What access does the attacker start with, what skill does it need, how many steps, how repeatable is it, and could it be automated across every customer at once?
Three or four bands on each axis is plenty. The temptation to add more factors — discoverability, reproducibility, affected users, damage potential — is exactly the path DREAD took, and the reason most teams left it behind: more factors did not produce more agreement, they produced more places to disagree, and averaging them flattened everything into the middle. If you already have CVSS scores from a scanner, treat them as an input to exploitability rather than an answer, for the reasons the comparison of CVSS to modelled risk sets out: a base score knows about the flaw and nothing about your system.
Score fast. A first pass over thirty threats should take under an hour, out loud, with the room disagreeing openly. Precision at this stage is false precision — the objective is to sort the list into roughly the right layers, and layers are robust to being one band off in either direction.
Three tie-breakers that do the real work
Two axes will leave you with clusters of equally scored items, and that is where prioritisation usually stalls into argument. Agree the tie-breakers up front, apply them mechanically, and the arguments stop being about individual items:
- Blast radius. Does compromising this affect one account or every account? A flaw a user can exploit against their own data and a flaw that yields something reusable against everyone are different categories of problem, whatever their scores say.
- Detectability. If this were exploited today, would you know? A threat you would catch within minutes is genuinely less urgent than an identically scored one you would learn about from a customer or a researcher. This is also the tie-breaker that generates the cheapest remediations, because "add an alert" is often available long before "redesign the flow" is.
- Reachability. How many boundaries does the attacker cross first? A threat behind authentication, behind a VPN, and behind an internal network sits lower than the same threat exposed to the internet — this is the defence in depth already on the diagram doing its job, and the model should get credit for it.
An attack tree is the fastest way to settle reachability disputes, because the depth of a branch and the number of preconditions on it are visible rather than asserted. When two people disagree about whether something is realistic, they are usually disagreeing about a step neither has stated out loud, and drawing the path surfaces it in a couple of minutes.
Band it; do not order it
Here is the step that saves the most time: you do not need a ranked list. You need to know what is being done now, what is queued, and what is not being done at all. Sort into five bands and stop.
| Band | What goes in it | What it commits you to |
|---|---|---|
| Fix now | High impact and reachable today. Usually three to six items out of sixty. | Named owner and a date this sprint. If everything is here, nothing is. |
| This quarter | Serious, but needing design work, a migration, or a dependency you do not control yet. | On the roadmap with an owner, not merely "agreed to be important". |
| Backlog | Real, lower severity, worth doing when the surrounding code is next open. | Nothing scheduled — but it stays visible and gets re-read at the next review. |
| Accepted | Not worth the cost of fixing, given this system and this data. | A named accepter, a written rationale, and a review date. |
| Escalate | The cost of fixing or of accepting is above the room's authority. | A decision request going somewhere specific, with a deadline. |
Only the first band needs internal ordering, and it is short enough to order by discussion in ten minutes. Everything below it needs to be in the right band, not in the right position — and band membership is a far more stable judgement than rank, which means it survives contact with the next sprint instead of needing to be recomputed.
Watch the size of the top band. If a third of the list lands in "fix now", the scoring was not discriminating and the exercise has handed the delivery team an unprioritised list wearing a priority label. Force the constraint: what would you fix if you could only fix four things before the next release? That question produces a better top band than any rubric, and it is the question your stakeholders are actually asking.
Group by fix, not by finding
A prioritised list of threats is still not a plan, because threats and fixes are not one-to-one. The last transformation before anything reaches a delivery team is to invert the list: cluster by the control that closes each item, and rank the clusters.
This changes the arithmetic in your favour. A centralised authorization check may close eleven entries at once. Removing a field from a payload may close four. Turning on an alert may not close anything, but it moves six items from "we would never know" to "we would know today", which is often the better use of the same afternoon. Ranked by threat, that alert is item nineteen; ranked by fix, it is one of the best-value pieces of work available.
Two things fall out of this view that a threat-ordered list hides. The first is the cheap-and-broad cluster — small effort, several entries closed — which should be done immediately regardless of where its members scored, because arguing about it costs more than doing it. The second is the expensive singleton: one high-severity threat whose only real fix is a re-architecture. That item does not belong in a sprint at all. It belongs in a design decision with a date on it, and pretending otherwise is how it rolls forward untouched for four quarters while accumulating a comment thread.
Write the clusters into the risk register as the unit of work, with the threats they close linked underneath. That way progress is visible as threats closing in groups, which is both more honest and considerably more motivating than watching a count of sixty-one decrease by one.
Accepting a risk is a decision, not a silence
Most of a long list will not be fixed. That is a normal, defensible outcome — but only if the not-fixing is recorded as a decision. An accepted risk and a forgotten risk look identical in a spreadsheet six months later, and only one of them is survivable in an incident review or an audit.
An acceptance needs four things: what is being accepted, why — in terms of cost and exposure rather than "low priority" — who accepted it, and when it will be looked at again. The who is the part teams get wrong. An engineer can accept an engineering cost, but not a business risk; if the consequence is regulatory exposure, customer data, or contractual failure, the accepter has to be someone who owns that consequence. Getting this right is also what makes the register usable as compliance evidence, where an auditor is looking for exactly this trail: identified, considered, decided, by a named person, on a date.
The review date matters more than it appears. Acceptances are conditional on facts — this data is not sensitive, this system is internal, this feature has forty users — and facts change silently. An acceptance with no expiry becomes a permanent, invisible assumption, which is precisely the shape of the finding that turns up in a post-incident timeline.
A worked pass, end to end
Concretely, on that list of sixty-one from a first session on a mid-sized SaaS product:
- 61 raw threats come out of the STRIDE sweep.
- Merging restatements takes it to 52 — the same session-handling threat had been raised at three different points on the diagram.
- Folding by root cause takes it to 34 distinct entries, resting on 9 underlying causes. The largest fold is 11 endpoint findings collapsing into one missing central authorization check.
- Striking non-threats and out-of-scope items takes it to 29, with 3 items reassigned to the platform team as documented assumptions.
- Scoring on two axes puts 5 in the top band, 8 in the quarter band, 11 in the backlog, and 5 as acceptance candidates.
- Grouping the top 13 by fix yields 6 pieces of work. Two of them close 9 of the 13 between them; one is a re-architecture that becomes a design ticket rather than a sprint item.
- What leaves the room is six work items with owners, five acceptances with names and review dates, and one escalation. Not a spreadsheet of sixty-one.
The whole pass is an afternoon, most of it in the collapsing step rather than the scoring. That ratio is the tell that the process is working: if you are spending most of your time scoring, you are scoring things that should have been merged.
Keeping the order true
Priorities decay, because the system moves. The fix is not to re-score everything on a calendar — that turns into a quarterly ritual nobody has time for and produces mostly the same answer. Re-rank on triggers instead: a new external interface, a change of authentication or authorization, a new class of data entering the system, a new integration or SDK, an incident anywhere in the sector that matches one of your branches, and any acceptance hitting its review date.
Each trigger touches a handful of entries, not the whole register, so the work is proportionate. And crucially, closing an item is also a trigger: fixing the top-band threat frequently changes the exploitability of two others, either because the path they shared is gone or because the attacker's cheapest route is now somewhere else entirely.
Where prioritisation goes wrong
- Ranking before collapsing. Scoring duplicates makes the list feel larger and the exercise feel futile. Merge first, always.
- Adding factors to win an argument. A sixth scoring dimension does not resolve a disagreement about impact; it hides it behind an average.
- Ordering all fifty. Positions 12 through 50 will never be acted on in that order. Bands are cheaper and more durable.
- A top band that holds a third of the list. If everything is urgent, the delivery team picks for you — usually by picking the easiest.
- Ranking threats and handing over threats. Teams ship fixes, not findings. Convert to fixes before the handover or the conversion happens ad hoc, in the sprint, by whoever is least equipped to do it.
- Silent non-fixes. Anything not being done and not written down as accepted is simply forgotten, and it will be discovered later by someone else.
- Ignoring effort entirely. Severity says what matters; effort says what is achievable this month. A plan built from only one of those is a wish list.
The measure of a good prioritisation pass is not the ordering. It is whether, two weeks later, something is demonstrably fixed and everyone can name what was consciously not fixed and why. A list that produces both is doing its job; a perfectly ranked list that produces neither is a document, not a control.
Regulated environments add a constraint worth modelling explicitly: some findings cannot be accepted at all, whoever signs. See threat modeling for healthcare and for fintech, or start from the pre-structured register in the risk register template.