Threat modeling is high-leverage and chronically skipped, because doing it well demands sustained, structured imagination under deadline.
An LLM is a strong brainstorming partner for exactly this: it can enumerate STRIDE threats across a data-flow diagram far faster than you can, propose attack trees, and — critically — run a completeness pass that hunts for the threats your first draft missed. Your job shifts from generating threats to judging them: pruning the implausible, catching what the model overlooked, and turning the survivors into mitigations you will actually build.
STRIDE maps one-to-one onto security properties — Spoofing→authentication, Tampering→integrity, Repudiation→non-repudiation, Information disclosure→confidentiality, Denial of service→availability, Elevation of privilege→authorization. Knowing the mapping lets you sanity-check any AI-generated threat list for whole categories left empty.
Skip the full ritual for a change with no new trust boundary and no new data flow; the value is proportional to how much the attack surface moved.
Describe the system as a data-flow, not prose. List external entities, processes, data stores, and every trust boundary crossed. Precision here determines the quality of everything downstream.
Prompt for a STRIDE enumeration per element. Force structure:
You are a threat-modeling assistant. Here is a data-flow description of
a feature I am designing (my own system). Enumerate threats using STRIDE.
For EACH element and EACH data flow that crosses a trust boundary,
list threats under all six STRIDE categories that apply. For each threat:
- the STRIDE category
- the element/flow it targets
- a concrete attacker scenario (one sentence)
- the security property it violates
Do not skip a category just because it seems unlikely — say "none
credible" explicitly if so, so I can see you considered it.
SYSTEM:
- External entity: unauthenticated web client
- Process: /api/export handler
- Data store: Postgres (customer records)
- Trust boundary: internet -> app; app -> database
Expected output: a threat table where every trust-boundary crossing has been examined under all six categories, with explicit "none credible" entries rather than silent gaps.
Build attack trees for the top threats. For the two or three highest-impact threats, ask for an attack tree — root goal, branching sub-goals, leaf techniques — so you can see the paths and pick where a single control cuts the most branches.
Build an attack tree for: "attacker exfiltrates customer records via
/api/export". Root = the goal; branches = distinct paths; leaves =
concrete techniques. Mark which leaves a single control would block.
Run a completeness pass — the step that catches what you missed. Start a fresh angle:
Here is my current threat list. Act as a skeptical reviewer: what threats
are MISSING? Specifically check for trust boundaries I did not list,
assumptions I am relying on that could be false, and threats that emerge
from combinations of elements rather than any single one.
Turn survivors into a mitigations table. For each retained threat: mitigation, owner, and whether it is designed-in, needs a control, or is an accepted risk. This is the artifact you carry into review.
Threat models describe architecture, which is often client-sensitive. Before prompting, abstract the design: replace product names, real hostnames, and proprietary logic with generic roles ("payment processor", "customer data store") and keep only the structure the threat model needs — entities, boundaries, data flows. That abstraction usually loses nothing for STRIDE, which cares about shapes not names. Where a client prohibits external tools, run a local model for enumeration and keep the artifact in the client's own Threat Dragon instance. Confirm tool approval before the first prompt and never paste real credentials, endpoints, or customer data into the model.