Draw the flow, mark the trust boundaries, ask what can go wrong, then turn the top findings into tickets. A useful first pass fits in an hour.
A small team can run a useful [threat model](/glossary/threat-modelling) in about an hour: draw how data moves through one core flow, mark where trust changes, ask what could go wrong at each point, rank what you find, and write the top items as tickets. You do not need a security specialist or special software for the first pass. You need the people who know the product, a whiteboard and a clear scope.
This article gives you the steps, a reusable prompt list and a worked example. The example is hypothetical and does not describe a real project.
Start with the four questions
Most threat modelling methods reduce to four questions, which the security community has popularised largely through Adam Shostack's writing on the subject. Use them as the agenda for the hour.
Keep the group small: a developer who knows the code, someone who owns product decisions, and a designer or tester if you have one. Three to five people is enough. Pick one flow, such as sign-up and payment, rather than the whole product.
Draw a data-flow diagram you can read in a minute
A data-flow diagram uses four shapes. **External actors** are people or systems outside your control, such as a customer or a payment provider. **Processes** are the parts of your system that do work, such as a web app, an API or a background job. **Data stores** are databases, file storage and caches. **Data flows** are arrows that show which data moves where.
Label every arrow with what travels along it (a password, a card token, a booking record) and how (HTTPS, a queue, a file upload). If the drawing needs more than about a dozen shapes, you have picked too much. Draw it on a whiteboard or a shared canvas such as FigJam, then photograph or export it so it can live next to the code.
Most attacks travel along a data flow, so a flow you forgot to draw is a flow nobody defended.
Mark the trust boundaries
A trust boundary is a line where the level of trust changes. Draw it as a dashed line across the diagram. Anything that crosses it deserves the most attention, because that is where you must check who is asking and whether the data is valid.
- The internet to your server: everything a browser or mobile app sends is input you do not control.
- Your system to a third party, such as a payment, email or analytics service.
- One user role to another: customer to staff, staff to administrator.
- One customer's data to another's, in any product that serves several organisations.
- Your own code to your build pipeline and cloud account.
Teams commonly forget the admin panel, background jobs, support tools and the deployment pipeline. They are often the least defended and the most powerful, so put them on the diagram.
Use STRIDE as a prompt list, not a form
STRIDE is a mnemonic for six kinds of threat. For each process, data store and boundary-crossing flow, ask each question and write down anything that makes the room uncomfortable. Skip a prompt that clearly does not apply.
| Threat | What it breaks | Question to ask |
|---|---|---|
| Spoofing | Proof of identity | Can someone pretend to be a user, a service or an admin? |
| Tampering | Integrity | Can someone change data in transit, in storage or in a request? |
| Repudiation | Accountability | Could someone deny an action because we kept no record? |
| Information disclosure | Confidentiality | Can someone read data they should not see? |
| Denial of service | Availability | Can someone make this slow, full or unavailable? |
| Elevation of privilege | Authorisation | Can someone do something their role does not allow? |
STRIDE is a prompt, not a complete list. If a worry does not fit a letter, write it down anyway, then cross-check against the [OWASP Top 10](/glossary/owasp-top-10).
Rank what you find
Expect ten to thirty findings. You cannot fix them all, so rank them. A three-level scale is enough: for each finding, rate how much damage it would do (low, medium or high) and how easy it would be to exploit (hard, moderate or easy). High damage and easy to exploit goes first.
Then choose one response per finding: **remove** the risk by changing the design, **reduce** it with a control, **transfer** it (for example, let a payment provider hold card data) or **accept** it. An accepted risk needs a name next to it and a date to look at it again, otherwise it is just a risk you forgot.
A worked example (hypothetical)
Imagine a small team building an appointment-booking app. Customers sign in with an email link, book a slot and pay through a third-party payment provider. Staff manage bookings in an admin panel. This is an invented example for illustration, not a real project.
The diagram has a customer, a web app, an API, a database, a payment provider and a staff admin panel. The team draws three trust boundaries: the internet to the API, the API to the payment provider, and customer to staff. Walking STRIDE across them turns up these findings:
- **Information disclosure:** booking pages use sequential numbers in the address, so a signed-in customer could change the number and read someone else's booking. This is the broken access control class of flaw listed in the OWASP Top 10.
- **Tampering:** the checkout request includes the price and the server trusts it, so a customer could edit it before sending.
- **Elevation of privilege:** the admin panel is reachable from the public internet and uses the same email link sign-in as customers.
- **Repudiation:** staff can issue refunds, but nothing records who did it.
- **Spoofing:** the sign-in link never expires and can be used more than once.
- **Denial of service:** the booking endpoint accepts unlimited requests, so a script could fill every slot.
Ranking by damage and ease puts three at the top: the booking access check, the price sent by the client and the open admin panel. The responses are concrete. Check booking ownership on the server. Calculate the price on the server. Put the admin panel behind [multi-factor authentication](/glossary/multi-factor-authentication) and a separate role. The rest go into the backlog.
Turn findings into tickets
A threat model is only worth the hour if it changes the plan. Write each decision as an ordinary ticket in the tracker the team already uses, next to feature work, with five parts:
- A one-sentence title that names the risk: customers can read other customers' bookings.
- Where it lives: the flow, the component and the boundary.
- The fix, written so a developer can start without asking.
- An owner.
- A done-when check, ideally a test: a request for another user's booking is refused.
Keep the diagram and the accepted-risk list in the repository, and review the accepted risks every time you re-run the model.
When to repeat it
Treat the model as a living drawing, not a document you finish. Re-run the relevant part when something changes:
- A new third-party service or integration.
- A new user role or a new way to sign in.
- A new kind of data, especially payments, health, identity or children's data.
- A new entry point, such as a public API or a mobile app.
- An incident or a near miss.
For small changes, a twenty-minute look at the diagram during design review is enough. We begin every project with a threat review and everyone on the team learns threat modelling; the [threat modelling service](/services/cybersecurity/threat-modelling) page describes what that looks like. For the wider picture, read the [guide to secure app development](/guides/secure-app-development).