Threat-model a small app: draw its data flows and trust boundaries, then find threats with STRIDE and choose fixes.
Why it matters
Most security work is reactive: a scanner finds a bug, an alert fires, a patch comes out. Threat modeling is the proactive part. Before (or while) a system is built, you ask "what could go wrong?" in an organised way, so problems get fixed on a whiteboard instead of in an incident report. It is cheap, it needs no special tools, and it is one of the most useful skills a security engineer can bring to a development team.
The core idea: four questions
A widely used framing, popularised by Adam Shostack and the Threat Modeling Manifesto, reduces threat modeling to four questions:
- What are we working on? Draw the system.
- What can go wrong? Find threats.
- What are we going to do about it? Choose mitigations.
- Did we do a good enough job? Review and revisit.
Step 1: draw a data flow diagram
A data flow diagram (DFD) needs only four shapes:
- External entities (rectangles): people or systems outside your control, such as a user or a payment provider.
- Processes (circles): your code, such as a web app or an API.
- Data stores (two parallel lines): databases, file storage, caches.
- Data flows (arrows): data moving between the others, labelled with what moves.
Then add trust boundaries: dashed lines wherever data crosses from one level of trust to another, such as the internet to your server or your server to a third-party API. Most threats live where arrows cross those lines.
Step 2: find threats with STRIDE
STRIDE, created at Microsoft, is a checklist of six threat types. Each one breaks a security property:
| Threat | Breaks | Example | Typical mitigation |
|---|---|---|---|
| Spoofing | Authentication | Logging in as another user with a stolen password | Strong authentication, MFA |
| Tampering | Integrity | Changing a price in a request before it reaches the server | Server-side validation, signatures, TLS |
| Repudiation | Non-repudiation | A user denies deleting a record and there is no evidence | Audit logs that users cannot edit |
| Information disclosure | Confidentiality | An error page shows a database password | Least privilege, encryption, generic errors |
| Denial of service | Availability | Flooding the login endpoint until the site falls over | Rate limits, quotas, scaling |
| Elevation of privilege | Authorization | A normal user reaches an admin page by changing the URL | Server-side access checks on every request |
Walk each element of the DFD, especially each flow that crosses a trust boundary, and ask "how could S, T, R, I, D or E happen here?"
Step 3: decide what to do
For each threat, pick one response:
- Mitigate: add a control (most common).
- Eliminate: remove the feature or data that creates the risk.
- Transfer: let someone better placed handle it (for example, use a payment provider instead of storing card numbers).
- Accept: document that the risk is low enough and who agreed to accept it.
Rank threats roughly by likelihood x impact so the team fixes the worst first. A simple high/medium/low scale is enough for beginners.
Worked example: a recipe-sharing app
The app lets people sign up, post recipes with photos, and comment. The DFD:
[User browser] --(login, recipes, photos)--> (Web app) --(SQL)--> ||Database||
(Web app) --(files)--> ||Photo storage||
(Web app) --(email)--> [Email provider]
- - - - trust boundary: internet | server - - - -
Walking STRIDE across the browser-to-app boundary gives, among others:
- S: password guessing on
/login. Mitigate with rate limits, lockouts and optional MFA. - T: a user edits the hidden
authorIdfield to post as someone else. Mitigate by taking the author from the session on the server, never from the request. - R: a user deletes another user's comment and claims they didn't. Mitigate with audit logs of deletions.
- I: uploaded photos keep GPS location in their metadata. Mitigate by stripping metadata on upload.
- D: someone uploads 2 GB files. Mitigate with a size limit and a per-user quota.
- E:
DELETE /recipes/42works for any logged-in user. Mitigate with an ownership check on the server.
Six concrete, fixable issues, found in about twenty minutes with a whiteboard. That is the whole point.
Common mistakes
- Boiling the ocean. Start with one feature or one diagram. A small model that gets used beats a perfect one that never finishes.
- Only thinking about outside hackers. Insiders, buggy integrations and honest mistakes cause incidents too.
- Treating it as a one-off. Update the model when the design changes: a new integration means a new trust boundary.
- Listing threats without owners. Each mitigation needs an owner and a ticket, or it will not happen.
Quick recap
- Threat modeling asks four questions: what are we working on, what can go wrong, what will we do, did we do enough.
- Draw a DFD with external entities, processes, stores, flows and trust boundaries.
- Use STRIDE (spoofing, tampering, repudiation, information disclosure, denial of service, elevation of privilege) on each element and boundary.
- Mitigate, eliminate, transfer or accept each threat, ranked by likelihood and impact.
Try it
Open the Do tab and threat-model a small to-do app on paper.