---
name: "threat_modeling"
description: "Run lightweight threat modeling on a feature or system: sketch a data-flow diagram with trust boundaries, walk STRIDE-lite over each element, rank the threats, and produce mitigation tickets. Use when designing a new feature or service, adding an API endpoint or integration, handling a new category of sensitive data, or preparing for a security review."
---

# Threat Modeling (STRIDE-lite)

## Purpose
Turn a feature design into a ranked list of concrete, product-specific threats with mitigations and owners, in about 30 minutes. Built for small teams without a security department.

## Workflow

### 1. Scope it (2 minutes)
Answer Shostack's four questions and write the answers down; they frame the whole session:
1. What are we working on? (one feature or bounded context, not the whole app)
2. What can go wrong?
3. What are we going to do about it?
4. Did we do a good job?

Keep the scope small. One data flow through one service beats a whole-system model you never finish.

### 2. Sketch the data-flow diagram (10 minutes)
Draw the feature as: external entities (users, third-party services) -> processes (endpoints, workers) -> data stores (databases, caches, queues), connected by data flows. Mark every **trust boundary** with a dotted line: anywhere privilege or control changes (client/server, service/database, your code/third-party, user/other-user's data).

One diagram per service or bounded context. A whiteboard photo or a Mermaid diagram in a doc beats a 40-page spec. See `references/dfd-guide.md` for symbols and a Mermaid starter template.

### 3. Walk STRIDE over each element (15 minutes)
For each element and each data flow crossing a boundary, ask which STRIDE categories apply and write the **concrete threat**, not the letter. "Attacker sets `userId` to another user's id" beats "E".

| | Threat | Breaks | Ask it as |
|---|---|---|---|
| S | Spoofing | Authentication | Could someone impersonate a user, service, or process here? |
| T | Tampering | Integrity | Could data or code be modified in transit or at rest here? |
| R | Repudiation | Non-repudiation | If this was abused, could the actor deny it? How would we know? |
| I | Information disclosure | Confidentiality | Does anything sensitive leave here, in responses, errors, or logs? |
| D | Denial of service | Availability | What happens if this is flooded, oversized, or exhausted? |
| E | Elevation of privilege | Authorization | Could a low-privilege caller reach high-privilege capability here? |

Use the per-element matrix in `references/stride-reference.md` to skip letters that don't apply to an element type. Don't argue about which letter a threat belongs under. Pick the property the attack actually breaks, record the row, move on.

### 4. Rank it (5 minutes)
Rate each threat on likelihood x impact, High/Medium/Low. Keep it to three levels; fake precision wastes the timebox. A fuller DREAD scoring rubric lives in `references/stride-reference.md` if you need it. Drop anything below Medium; a 5-10 row register is the goal.

### 5. Decide on each row
For every kept threat, pick exactly one: **mitigate** (name the control, prefer platform-level over app-level), **avoid** (remove the capability), **transfer** (push to a provider or insurer), or **accept** (named person signs off, recorded in the register). Then close the loop:
- Every mitigated threat becomes a backlog ticket with an owner and a date. No owner, no action.
- Accepted threats go on the risk register with the acceptor's name. Silent ignoring is not acceptance.

### 6. Review
Answer question 4: did we do a good job? Sanity checks: does the register cover the riskiest data flow? Would a second engineer reach the same rows? Re-run the model whenever a change crosses a trust boundary, adds an external integration, or touches a new category of sensitive data.

## Output Contract
Deliver three things:
1. **The DFD** (Mermaid, ASCII, or a described whiteboard sketch) showing entities, processes, stores, flows, and trust boundaries.
2. **The threat register** (markdown table): ID, element, STRIDE letter, concrete threat, likelihood, impact, decision (mitigate/avoid/transfer/accept), owner, mitigation.
3. **Residual risk statement**: the accepted threats in one paragraph, with who accepted them.

## Operating Rules
1. Concrete threats only. Never invent vulnerabilities, CVEs, or attacker capabilities you haven't verified. Unverifiable = cut it or label it an assumption.
2. 30-minute timebox per feature. When the time is up, the register ships as-is and the rest goes to the backlog.
3. Product-specific beats generic. "SQL injection" on every row is a smell; the register should read like this feature, not any feature.
4. The conversation is the value. If the team leaves with shared understanding of the riskiest flow, the session worked even if the doc is thin.
5. Retrigger, don't freeze. Architecture drifts in months; a frozen threat model is fiction.
