Security architecture principles: threat modeling to secure defaults
coreintermediateThreat modeling is the exercise of asking, for a specific system, who would attack it, how, and what they would gain — done before or during design, not after an incident. Attack surface is everything an attacker could touch: every endpoint, input field, dependency and open port, and a smaller surface is easier to defend than a larger one. Least privilege means every user, service and process gets only the access it needs to do its job, nothing more. Defense in depth means stacking multiple independent security controls so one failure does not mean total compromise. Secure defaults means the out-of-the-box configuration is the safe one, so a team that changes nothing is still reasonably protected.
Think of it as
Think of securing a building. Threat modeling is walking the property asking "who wants in, and how would they try" before you buy locks. Attack surface is every door, window and vent — the fewer of them, and the fewer left unlocked, the less a guard has to watch. Least privilege is giving each employee a key only to the rooms their job requires, not a master key "just in case." Defense in depth is a locked door behind a fence behind a guard behind an alarm — a burglar who beats one layer still has to beat the next. Secure defaults is the building shipping with the alarm already armed, not waiting for someone to remember to turn it on.
What we're doing: Apply threat modeling to a new "export my data" API endpoint before it ships.
- 8
- Spoofing here is not about fake credentials — it is about whether the URL's :id is actually checked against the caller's own identity, a broken access control bug if it is not.
- 14
- Information disclosure is the single most common finding a threat model catches before ship: a join or a serializer that returns more than intended.
- 22
- Each answer in step 3 is a concrete control, not a vague intention — this is what turns threat modeling into work that actually happens.
Why this works: Threat modeling before writing the endpoint surfaces the authorization check and the field-leak risk while they are a one-line fix in code review, instead of after the endpoint has shipped and a user notices they can read someone else's export by changing the ID in the URL.
Treating threat modeling as a one-time document instead of a per-feature habit
Wrong
Better
What you see: A system's original threat model correctly covers the five endpoints that existed at launch, but eleven new endpoints have shipped since with no equivalent review — the actual attack surface has more than doubled while the documented one has not moved, so nobody is asking the STRIDE questions for the eleven endpoints most likely to have a fresh, unreviewed bug.
Why: Attack surface changes with every feature, not just at initial design — a threat model that is never revisited describes a system that no longer exists. Treating it as a recurring, lightweight step per feature keeps it matched to what is actually deployed.
- Network — database not reachable from the public internet
- Identity — least-privilege, per-service credential
- Application — parameterized queries, input validation
- Data — sensitive columns encrypted at rest
- Detection — audit logs alert on anomalous query patterns
Remember: Threat model per feature, not once; shrink the attack surface before defending it; grant least privilege to humans and services alike; stack independent layers (defense in depth) since any one control can fail; ship secure by default so an unconfigured system is still reasonably safe.
See also: secrets audit logs and key rotation · common vulnerability classes

