Skip to content
JavaAgentic

Type at least two characters. Try “RAG”, “pgvector” or “tool calling”.

Threat Modelling

Finding design flaws before they ship: drawing data flow diagrams, applying STRIDE per element, prioritising with DREAD, and running a session that produces actionable work.

Advanced6 min readUpdated
On this page

Threat modelling asks a question testing cannot: what could go wrong with this design? It finds architectural flaws — a missing trust boundary, an unauthenticated internal call — that no scanner detects because the code correctly implements a flawed design.

Key Takeaways

  • Draw the data flow and mark trust boundaries — most threats cross one.
  • Apply STRIDE per element rather than brainstorming freely; coverage comes from the structure.
  • Prioritise by impact and likelihood, not by how alarming a threat sounds.
  • Every threat gets a decision: mitigate, accept or transfer.
  • The output is a backlog with owners, not a document.

Draw the system

Four element types: external entities in red, processes, data stores, and data flows. Trust boundaries sit where control changes hands — at the gateway and at the third party.

Trust boundaries are the crossings that matter: internet to gateway, gateway to internal network, application to database, your system to a third party. A threat that crosses one is where an attacker gains something.

Be honest about what is inside a boundary. "Internal network" is not a trust boundary if any compromised pod can reach any service — that is one large boundary containing everything, which is precisely the observation zero-trust design responds to.

STRIDE

ThreatQuestionTypical mitigation
SpoofingCan someone pretend to be another identity?Authentication, mTLS
TamperingCan data be modified in transit or at rest?TLS, signatures, integrity checks
RepudiationCan someone deny an action?Audit logging, non-repudiation
Information disclosureCan data leak?Encryption, access control, output filtering
Denial of serviceCan availability be destroyed?Rate limiting, quotas, timeouts
Elevation of privilegeCan someone gain unauthorised rights?Authorisation, least privilege

Apply it element by element. Free-form brainstorming misses categories; walking each element through six prompts gives coverage.

worked example — flow 2: gateway to order service
S: Can something other than the gateway call the order service directly?
   → Yes. Pod networking permits it and the service trusts X-User-Id.
   → MITIGATE: validate the JWT in the service; NetworkPolicy restricting ingress.
 
T: Can the JWT be modified in transit?
   → Signature prevents modification, but the hop is plaintext HTTP.
   → MITIGATE: mTLS between services.
 
R: Can a user deny placing an order?
   → Currently yes; we log the request but not the authenticated subject.
   → MITIGATE: audit log with subject, timestamp and correlation id.
 
I: Can order data leak to another user?
   → Object-level authorisation is checked in the controller but not in the
     batch export endpoint.
   → MITIGATE: scope the export query by customer; add a negative test.
 
D: Can one user exhaust the service?
   → No per-user limit on the search endpoint, which fans out to the database.
   → MITIGATE: per-user rate limit weighted by operation cost.
 
E: Can a user become an admin?
   → The role claim is read from the JWT; the auth server controls issuance.
   → ACCEPT: dependent on auth server integrity, which is modelled separately.

Notice how many outputs are ordinary engineering tasks. Threat modelling mostly surfaces work you would agree with once someone asked the question.

Prioritising

DREAD scores each threat one to three on damage, reproducibility, exploitability, affected users and discoverability. It is rough and it is enough — the purpose is ordering, not precision.

ThreatDREADiTotalDecision
Direct service call bypassing the gateway3323213Mitigate now
Export endpoint leaks other customers3333214Mitigate now
No per-user rate limit on search2332313Mitigate this quarter
Plaintext hop between services211318Mitigate with the mesh rollout
Auth server compromise311319Transfer — modelled separately

Resist over-engineering the scoring. Teams spend hours arguing whether exploitability is 2 or 3, which changes nothing about the order of work. Rough scores, quick decisions, move on.

Running a session

Before: someone draws the data flow diagram and circulates it. Doing this live wastes the room's time and the diagram is better when one person has thought about it.

In the room, ninety minutes with three to six people — the engineers who built it, someone with security knowledge, and ideally someone from operations who knows how it actually runs. Walk each element through STRIDE. Record every threat without debating fixes; the fix discussion derails coverage.

After: score, decide, and file tickets. A threat with no ticket did not happen.

Three questions unlock most sessions when the room goes quiet. What is the worst thing an attacker could do here? What would we most hate to explain to a customer? What are we assuming, and what if that assumption is false?

Accepting risk

Not every threat gets fixed, and pretending otherwise makes the model dishonest. Record acceptances explicitly:

accepted risk
THREAT: A compromised auth server could issue tokens for any user.
IMPACT: Complete authentication bypass.
LIKELIHOOD: Low — hardened, isolated, monitored, separately modelled.
DECISION: ACCEPT
RATIONALE: The alternative is a second independent authentication factor on
           every request, which the latency budget does not permit.
COMPENSATING: Anomaly alerting on token issuance rate; 15-minute token expiry;
              quarterly review of auth server access.
OWNER: platform-security   REVIEW: 2027-01-15

An acceptance with an owner and a review date is a decision. One without either is an omission with better paperwork.

Keeping it current

A model reflects the design at a moment. Re-examine when a new external integration appears, when a trust boundary moves, when a new data classification enters the system, or after any security incident — the incident is evidence the model missed something.

Store models in the repository next to the code so they are versioned, reviewable in pull requests, and visible to the people changing the system.

What to take away

Draw the data flow, mark the trust boundaries honestly, and walk each element through STRIDE rather than brainstorming. Score roughly and decide quickly. Turn every threat into a ticket with an owner, record accepted risks with a review date, and keep the model in the repository so it changes when the system does.

Frequently Asked Questions

When should we threat model?
At design time for anything new that handles sensitive data or crosses a trust boundary, and again when the architecture changes materially. A model built after the code ships still finds real issues, but the fixes are more expensive and some will not get made.
Do we need a tool?
No. A whiteboard and STRIDE applied to a data flow diagram finds most of what a tool would. Threat Dragon or the Microsoft tool help with documenting and tracking over time, which matters once you have a dozen models to keep current.
How do we stop it becoming a document nobody reads?
Every identified threat becomes a ticket with an owner and a decision — mitigate, accept, or transfer. A model whose output is a wiki page produces nothing; one whose output is a prioritised backlog changes the system.

Related tutorials