
What Threat Modeling Is Actually For
The purpose of threat modeling is to identify what can go wrong before it does, and to make specific decisions about what to do about it. Not to produce a comprehensive taxonomy of every possible attack. Not to satisfy a compliance checklist. The output that matters is a short list of concrete decisions: which controls to add, which attack surfaces to harden, which assumptions to validate before the code ships.
A threat model does not need to be a formal document to fulfill this purpose. It can be a 30-minute conversation with two or three people and a set of notes. The conversation needs to cover four questions: what are we building, what can go wrong, what are we going to do about it, and how will we verify we did it. This framing, which Microsoft's SDL team formalized years ago, is useful precisely because it fits inside a design review without requiring a dedicated security architect to run it.
The Data Flow Diagram as a Starting Artifact
Before asking "what can go wrong," you need a picture of where data flows. This does not require formal DFD notation or dedicated tooling. A whiteboard sketch with boxes for systems and arrows for data movements is sufficient. The key elements are external actors (who initiates requests), data stores (where data persists), processes (what transforms data), and trust boundaries (which boundaries a request crosses when moving between components).
Trust boundaries are where the interesting security properties live. When data crosses from an external actor to your API, the trust level changes. When a service call crosses from your application to a third-party API, the trust level changes. When a background job reads from a message queue, that crossing is also a trust boundary. Each trust boundary crossing is a candidate for a threat, and the diagram makes those crossings visible.
For a typical SaaS web application: the browser is an external actor, the API is a process, the database is a data store, and any external service integration is another actor at a trust boundary. Start with those four elements. You can add detail for specific components, but you do not need to before the first session becomes useful.
Applying STRIDE Selectively, Not Mechanically
STRIDE (Spoofing, Tampering, Repudiation, Information Disclosure, Denial of Service, Elevation of Privilege) is a structured way to ask what can go wrong at each trust boundary. You do not need to apply all six categories to every component. You need to apply the categories that are plausible given the component type and the data it handles.
For an API endpoint that takes user input and writes to a database, the productive STRIDE questions are Tampering (can I alter another user's data?), Information Disclosure (can I read data I should not see?), and Elevation of Privilege (can I call this endpoint with permissions I do not have?). Repudiation is less likely to be relevant unless you have explicit non-repudiation requirements. Apply the categories selectively based on what the component does, not mechanically to every element in the diagram.
A lightweight session on a new file upload feature might produce notes like these:
- Trust boundary: browser to upload API
- Tampering: are we validating file type by content signature, not just the extension?
- Information Disclosure: does the upload response expose internal storage paths or other users' file IDs?
- DoS: is there a file size limit and a rate limit per account on the upload endpoint?
- Trust boundary: API to storage service
- Elevation of Privilege: can the storage bucket policy be read by one tenant in a way that reveals another tenant's paths?
- Tampering: is the storage key namespaced per tenant, or is isolation enforced only at the API layer?
Five questions. If any answer is "we have not checked," that is an action item. The session takes 20 minutes and surfaces issues that a scanner would not find because they require understanding the authorization model.
Common Shortcuts That Cause Misses
The most consistent threat modeling failure in small teams is scoping to the happy path. The feature works correctly under normal conditions; the data flows as designed; the happy path is secure. The threats live in the edge cases: what if the user is not who they claim to be, what if the input is malformed, what if the API is called out of the intended sequence, what if the third-party service returns unexpected data?
A second common miss is treating authentication as the only access control boundary. Authentication verifies identity. Authorization verifies permission. A threat model that checks "is the user authenticated" at every boundary and stops there will miss IDOR, privilege escalation through role confusion, and horizontal access control failures where a user accesses another user's resource by guessing or enumerating a resource ID.
Third: overlooking backend-to-backend calls. In microservice architectures, the externally-facing API often calls several internal services. If those internal services trust any caller that originates from inside the VPC, then compromising one service exposes all of them. The trust boundary between internal services is real and is worth including in the diagram, even if adding controls there feels inconvenient.
A Note on Formality
We are not arguing against formal threat models for high-risk components. An authentication flow, a payment processing path, or a system handling regulated data warrants more depth than a 30-minute session can provide. Full STRIDE with a dedicated security architect, formal documentation, and structured review is appropriate for those contexts, and the overhead is justified.
The point is that the overhead of a formal exercise should not be the reason a team does no threat modeling at all. Most teams will get more security value from a lightweight, consistently applied process than from occasional formal exercises followed by months with no security design discussion. The lightweight approach described here is a baseline that keeps security questions in the room during design, not a substitute for depth on the components where that depth is warranted.
The cost of a 20-minute threat model session at design time is 20 minutes. The cost of a missing access control check found in production is a vulnerability report, a remediation sprint, and a conversation with affected users. The arithmetic is not complicated, and it does not require a dedicated security architect to run the calculation.


