Classic STRIDE asks six questions (spoofing, tampering, repudiation, information disclosure, denial of service, elevation of privilege) about every element of a system. On a diagram with 20 elements that's 120 questions, many of which make no sense: you can't really "spoof" a database table. STRIDE per element fixes that by applying only the categories that fit each element type.
The STRIDE per element chart
This chart comes from Microsoft's Security Development Lifecycle guidance, where it was used to drive the Microsoft Threat Modeling Tool. It uses the four element types of a data flow diagram:
| Element | S | T | R | I | D | E |
|---|---|---|---|---|---|---|
| External entity (user, third-party system) | ✓ | ✓ | ||||
| Process (service, function, worker) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Data store (database, bucket, queue, cache) | ✓ | ✓* | ✓ | ✓ | ||
| Data flow (request, message, file transfer) | ✓ | ✓ | ✓ |
* Repudiation applies to data stores that hold logs or audit records, because tampering with them lets someone deny an action.
Why each element gets the categories it does
- External entities are outside your control, so you can't tamper-proof them. What you can ask is whether someone can pretend to be them (spoofing) and whether they can deny something they did (repudiation).
- Processes run code, hold identities and make decisions, so every category applies. They're where most threats are found.
- Data stores hold data at rest: it can be changed, read or made unavailable. They don't act on their own, so spoofing and elevation are recorded against the process that uses them.
- Data flows carry data in transit: it can be altered, intercepted or blocked. Forged data on a flow is recorded as spoofing of whatever sent it.
Going further: STRIDE per interaction
STRIDE per element looks at each element alone, which can miss threats that only appear where two elements meet. STRIDE per interaction takes each interaction (source, data flow, destination) as the unit, and is most useful for flows that cross a trust boundary. A webhook from a payment provider into your API is a good candidate: the interesting threats (forged events, replayed events, events for the wrong account) only make sense when you consider sender, flow and receiver together.
A practical compromise: use per element for the whole diagram, then per interaction for every flow that crosses a trust boundary.
Worked example: Invoicely
Applying the chart to five elements of the Invoicely DFD, and keeping only the questions that produced a real threat:
| Element | Type | Applied | Threat found |
|---|---|---|---|
| Customer | External entity | S, R | S: credential stuffing on login (T1) |
| Web API | Process | S, T, R, I, D, E | I: IDOR on invoice endpoints (T2); T: stored XSS in invoice notes (T7) |
| File storage | Data store | T, I, D | I: invoice PDF links never expire (T3) |
| Stripe webhook | Data flow | T, I, D | T: forged payment events if the signature isn't verified (T4) |
| Admin console | Process | S, T, R, I, D, E | E: shared database role (T5); R: no audit log (T6) |
Notice that T4 is really a per-interaction finding: the threat only exists because of who sends the webhook and what the API does with it.
How to run it
- Draw the DFD, with trust boundaries. Our guide to building a DFD covers the level of detail.
- List every element with its type. Start with the elements that sit on or touch a trust boundary.
- For each element, ask only the questions in its row of the chart. Write each answer as a threat statement or mark it "not applicable" quickly.
- For each flow that crosses a trust boundary, do a per-interaction pass.
- Pick the most serious threats and decompose them into attack trees to find the cheapest place to break them.
Common mistakes
- Using the chart as a filter. If you find an elevation-of-privilege threat against a data store, write it down; it's probably really about the process that uses it.
- Treating every element equally. Internal elements far from any trust boundary rarely need the same time as the API gateway.
- Diagram too abstract. If "Backend" is a single process, STRIDE per element will find generic threats. Split it until each process has one main job.
Key takeaways
- STRIDE per element applies only the STRIDE categories that can affect each DFD element type, which cuts the number of questions to ask by roughly half.
- Processes get all six categories; external entities only spoofing and repudiation; data flows tampering, disclosure and denial of service.
- Elements on a trust boundary deserve the most time; STRIDE per interaction goes further by analysing each flow across a boundary.
- The chart is a starting point, not a filter: a finding outside it is still a finding.
Frequently asked questions
What is STRIDE per element?
A variant of STRIDE, documented as part of Microsoft's Security Development Lifecycle, that uses a chart to decide which of the six STRIDE categories to apply to each type of data flow diagram element. It makes STRIDE faster and more consistent.
Why can't a data flow be spoofed in STRIDE per element?
Spoofing is about an identity, and a data flow has no identity of its own. The threat "someone sends forged data on this flow" is recorded as spoofing of the process or entity at the sending end, or as tampering with the flow.
What is the difference between STRIDE per element and STRIDE per interaction?
STRIDE per element analyses each element on its own. STRIDE per interaction analyses each interaction, a source, a flow and a destination together, which is better at finding threats that only appear where two elements meet across a trust boundary.
Do I have to use the STRIDE per element chart exactly?
No. Treat it as a checklist of the minimum questions. If you find a threat in a category the chart doesn't list for that element, record it anyway.