Threat modelling is one of the most useful security activities I can do before writing code. It brings developers, product people, operations, and security into the same conversation: what are we building, what could go wrong, and what are we going to do about it?
The output is not a perfect diagram or a large document. It is a shared understanding of risk and a short list of actions the team can own.
I use the four-question structure popularised by the Threat Modeling Manifesto and OWASP:
That is enough to run a useful first session. A framework such as STRIDE can help the team think, but the framework should support the conversation rather than dominate it.
I keep the first session to about an hour and invite people who understand the product, architecture, operations, and security. Before the meeting, I prepare a simple system and data-flow diagram.
Pick one feature or flow. “Threat model the platform” is too broad. “Register a vehicle and let its owner view it” is workable.
List the important assets and trust boundaries:
I ask everyone to complete a sentence:
Someone or something can by , which would cause ___.
Plain threat statements are easier to discuss than isolated security terms. “A signed-in user can change the vehicle ID in an API request and read another customer’s record” gives the team something concrete to test and fix.
For each important threat, record prevention, detection, and recovery where they make sense. A control needs an owner and a way to verify it.
“Use access control” is not an action. “The API checks the authenticated customer ID against the vehicle owner for every read, covered by an integration test” is.
Not every risk needs immediate engineering work. The team can mitigate, avoid, transfer, or consciously accept a risk. Record the decision and the person accountable for it.
Imagine a vehicle registration service with a web application, an API, an identity provider, and a database.
| Threat | Useful control | How I would verify it |
|---|---|---|
| A user reads another owner’s vehicle | Object-level authorisation in the API | Integration tests with two user accounts |
| Automated fake registrations | Rate limits, abuse signals, and staged verification | Load and abuse-path tests |
| Sensitive data appears in logs | Structured logging with field allow-lists | Log inspection in a test environment |
| A stolen service credential reads the database | Managed identity and least privilege | Permission review and denied-action tests |
| A retry creates duplicate records | Idempotency key on registration | Repeat the same request under failure |
The point is not to name every possible attack. It is to identify the paths with meaningful impact and make the design better before they become incidents.
An AI feature adds new components and less deterministic behaviour, but it still sits inside an ordinary software system. I threat model the complete path, not only the model.
I pay particular attention to:
The controls are familiar engineering controls applied carefully: isolate untrusted content, constrain tools, validate outputs, enforce authorisation outside the prompt, require approval for risky writes, and monitor unusual behaviour.
Telling the model to “ignore malicious instructions” is not a sufficient control.
A threat model goes stale when the system changes. I revisit it when the team adds a new data source, tool, external integration, permission model, or high-impact action. Incidents and near misses are also useful triggers.
The threat list should connect to normal work:
If nobody uses the document after the workshop, the process has failed.
I avoid these patterns:
Threat modelling works best as a small, repeated design habit. It does not remove risk, but it makes risk visible early enough for the team to make a deliberate choice.
Legal Stuff
