What a threat model actually looks like when it is finished
Most organizations that say they do threat modelling have a diagram. It was drawn during a workshop, it is eighteen months old, and the system it describes has since grown two integrations and a mobile client. A threat model is not that diagram. It is a document the team maintains, and its value is almost entirely in being current.
The short version
A finished threat model contains a decomposition of the system, the trust boundaries drawn on it, an enumerated list of threats tied to those boundaries, a decision for each threat, and a set of backlog items with owners. It is written by the people who build the system, it is revised when the system changes, and it produces work rather than reassurance.
A risk register records what could go wrong for the organization and who owns it. A threat model records how a specific system could be attacked and what in the design stops it. One feeds the other; neither replaces it.
Decomposition: what the system is made of
Start by writing down what exists: processes and services, the data stores they read and write, the external entities that talk to them — users, administrators, third-party services, scheduled jobs — and the flows between all of these. Each flow carries something, over some protocol, authenticated somehow, and each of those three facts matters.
The useful level of detail is the level at which somebody could reach something they should not. A single box labelled “backend” hides the question of whether the reporting service and the payment service share a database credential, which is usually the question worth asking.
Two artifacts that are frequently missing and always revealing: the list of identities each component runs as, and the list of secrets each one can read.
Trust boundaries, and why drawing them is the hard part
A trust boundary is a line across which the level of trust changes. Between the internet and your edge. Between an unauthenticated and an authenticated user. Between one tenant and another. Between your code and a library you did not write. Between the application and the database it queries with a privileged account.
Drawing them is the hard part because it forces the team to say out loud what they trust, and disagreements surface immediately. One engineer believes the internal message bus is a trusted network; another knows a partner integration publishes to it. Where the drawing is contested is where the interesting threats are, and time spent arguing about a line is the most productive part of the exercise.
The boundary that is most often missed sits between your own components — the assumption that anything already inside the perimeter can be trusted, which is the assumption every lateral-movement finding depends on. Architecture work that starts from boundaries rather than from components is described in security architecture and threat modelling.
Enumerating threats: STRIDE as a prompt
STRIDE — spoofing, tampering, repudiation, information disclosure, denial of service, elevation of privilege — is a set of prompts. Walk each element and each flow and ask the six questions of it. The output is not “we have covered STRIDE”; the output is a list of specific, concrete threats expressed in the language of your system.
Where the prompts run out, use a published list appropriate to the component. For web-facing components the OWASP Top 10:2025 gives ten categories that are worth walking against every boundary. For any component with a model in it, the OWASP Top 10 for LLM Applications 2025 is the equivalent list, and MITRE ATLAS is the public knowledge base of adversary behaviour against machine learning systems. What changes when a model is one of the components is the subject of AI threat modelling.
Treating any of these as a checklist to complete is the failure mode. They are there to stop the room running out of ideas, not to define the finish line.
Recording a threat properly
A threat recorded as “SQL injection” is not recorded. A threat is worth writing down when it names the boundary it crosses, the asset it reaches, and the assumption it breaks.
Generic worked example — not a client system
Threat. A user of tenant A supplies a record identifier belonging to tenant B to the export endpoint.
Boundary crossed. Tenant isolation.
Asset reached. Another customer’s records, in bulk, via a file the system generates.
Assumption broken. That the identifier was issued to the caller, because the export path filters by identifier and the read path filters by tenant.
Decision. Mitigate. Move the tenant predicate into the data access layer so no query can omit it, and add a test that fails if a query is built without one.
That example is invented to show the shape and describes no real system. The value of the format is in the third and fourth lines: naming the broken assumption is what turns a threat into a design change rather than a patch.
Deciding what to do
Every enumerated threat gets one of four decisions, and the decision is recorded with a name against it.
- Design it out. Change the system so the threat cannot exist. The most expensive at the time and the cheapest over the life of the system.
- Mitigate. Add a control that reduces the likelihood or the impact, and say how you will know it is working.
- Transfer. Move it to somebody contractually better placed — a processor, an insurer — knowing that the consequence rarely transfers with it.
- Accept. Record who accepted it, on what basis, and when it should be revisited. An acceptance with no name on it is an omission wearing a decision’s clothes.
Mapping mitigations to work
A threat model that does not produce backlog items has not finished. Each mitigation becomes an item with an owner, an acceptance criterion and a place in a sprint — and, where possible, a test that fails without the control. A mitigation with a test attached survives refactoring; one that lives only in a document does not. That connection between the model and the pipeline is where secure development starts.
Keep the identifier stable. When a finding turns up later in a report, being able to say “this is the threat we accepted in March, here is who accepted it” is worth the small discipline of numbering.
What the finished document contains
- Scope: which system, which version, which date, and who was in the room.
- The decomposition, with the diagram and the element list it was drawn from.
- Trust boundaries, named, with the trust assumption each one encodes stated in a sentence.
- The threat list, each entry in the format above.
- Decisions, with owners and dates, including the acceptances.
- Backlog items, linked to the tracker.
- Open questions — the things the room could not resolve, which is often the most useful section.
It is a working document rather than a report, but it is written to be read by somebody who was not there. The same standard applies as to any other deliverable: a worked example of how one finding is written up is the closest thing on this site to the tone a good threat entry takes.
Keeping it alive
Revisit it whenever a trust boundary moves: a new integration, a new class of user, a new data store, a component moved between networks, or any change that alters who can reach what. In practice that means attaching the question to something that already happens — a design review, an architecture decision record, the checklist on a pull request that adds a new external call. A quarterly reminder to review the threat model is an appointment everybody moves.
The people who build the system write it, with somebody experienced in attacks asking the questions. A threat model produced entirely by an outsider describes a system nobody recognizes and is abandoned within a quarter. The right arrangement is usually a facilitated first pass, then the team maintaining it, with somebody from outside reading it once or twice a year and asking the awkward questions.
How the work is bounded
The scope is agreed in writing before work starts, and the engagement is quoted in writing with it.
SecHB does not issue certifications, attestations or audit opinions: those come from accredited certification bodies, CPA firms and QSAs. The work here is what an organization does to be ready for them.
Nothing here is legal advice. Where a question turns on the law, the work is done alongside the client’s counsel, not instead of them.
Questions we are asked
Do we need a threat modelling tool?
No tool is required. A threat model can live in a markdown file beside the code, and the ones that stay current usually do, because a document that needs a licence to open is a document that stops being read.
Who should write the threat model?
The people who build the system write it, with somebody experienced in attacks asking the questions. A threat model produced entirely by an outsider describes a system nobody recognizes and is abandoned within a quarter.
How often should a threat model be revisited?
Revisit it whenever a trust boundary moves: a new integration, a new class of user, a new data store, a component moved between networks, or any change that alters who can reach what.
How is a threat model different from a risk register?
A risk register records what could go wrong for the organization and who owns it. A threat model records how a specific system could be attacked and what in the design stops it. One feeds the other; neither replaces it.
Starting one
Send an architecture diagram, however rough, and a sentence about what the system must never do. The reply names the first three trust boundaries worth arguing about. More of our writing is indexed at writing.