Security No. 291

Threat Modeling skill for Claude Code

Find design flaws before they become incidents. Gives Claude a disciplined STRIDE process instead of a generic list of scary threats. It builds a Mermaid data flow diagram from your code and configs, marks trust boundaries, enumerates threats per element, cites existing controls by file, and ranks residual risk. The output is a versioned model document with owners, tickets, and explicitly accepted risks.

  • namethreat-modeling
  • size189 lines · ≈2,000 tokens
  • files1
  • licenseMIT
  • updated

What Claude sees before loading it

This description is the only part of the skill that sits in context all the time. Claude reads it to decide when to load the full playbook below.

description: Builds STRIDE threat models for systems and features — data flow diagrams in Mermaid, trust boundaries, per-element threat enumeration, existing and missing mitigations, and a risk-ranked action list. Use when designing a new service or feature, before a security review, when adding a third-party integration, handling sensitive data, crossing a new trust boundary, or when asked to "threat model this", "what could go wrong", or "STRIDE".

Try asking

  • Threat model the new Stripe webhook and payout flow before we build it
  • We're adding SSO with Okta — what could go wrong? Use STRIDE
  • Create a threat model doc for our file-sharing service and rank the risks

Use it when

  • A new service, feature, or integration is being designed
  • Sensitive data or money starts flowing through a new path
  • A compliance review or security team asks for a threat model
  • An existing architecture needs a prioritized list of security gaps

Skip it when

  • You need a line-by-line review of existing code — use owasp-review instead
  • The task is diagram notation itself rather than risk — use c4-diagrams instead

How to check the result

Every boundary-crossing flow in the diagram has threats considered, every existing mitigation cites a file or setting, and every High or Critical risk has an owner and ticket.

The common mistake it prevents

Treating traffic inside the VPC as trusted and skipping the compromised-internal-service scenario, which is exactly how lateral movement succeeds.

~/.claude/skills/threat-modeling/SKILL.md

--- name: threat-modeling description: Builds STRIDE threat models for systems and features — data flow diagrams in Mermaid, trust boundaries, per-element threat enumeration,… license: MIT ---

A threat model is done when it answers four questions with evidence: what are we building (a diagram that matches reality), what can go wrong (threats tied to specific elements and boundaries), what are we doing about it (mitigation per threat, existing or planned, with an owner), and did we do a good job (review against the diagram and open risks accepted by name).

Ground rules

  • Model the system as it is or will be built, from code, configs, and architecture docs. Ask the user when the data flow is unknown; never invent components.
  • Threats attach to diagram elements and to flows crossing trust boundaries. A threat with no element is a brainstorm, not a model.
  • Prefer ten specific, ranked threats over fifty generic ones.
  • Scope one feature or service per model. A whole company in one diagram is unreadable.

Workflow

- [ ] 1. Define scope, assets, and security objectives
- [ ] 2. Draw the data flow diagram (DFD) with trust boundaries
- [ ] 3. Enumerate threats per element with STRIDE
- [ ] 4. Record existing mitigations from code/config
- [ ] 5. Rank residual risk
- [ ] 6. Decide: mitigate, transfer, accept, or eliminate — with owners
- [ ] 7. Write the model document and validation notes

1. Scope and assets

Write down:

  • In scope: the feature/service, its data stores, its external dependencies.
  • Assets: what an attacker wants — credentials, PII, payment data, tenant data, signing keys, compute, availability, reputation.
  • Actors: anonymous users, authenticated users per role, admins, internal services, third parties, operators with prod access.
  • Assumptions: e.g. “TLS terminates at the load balancer”, “the IdP is trusted”. Assumptions are where real attacks live; list them explicitly so they can be challenged.

Gather evidence before drawing:

ls docs/ adr/ architecture/ 2>/dev/null
grep -rnE "https?://[a-z0-9.-]+" --include=*.{env.example,yaml,yml,toml,json} . | grep -v node_modules | head -50
grep -rniE "s3|bucket|queue|sqs|pubsub|kafka|redis|postgres|mongo|stripe|twilio|webhook" --include=*.{ts,js,py,go,yaml,tf} . | cut -d: -f1 | sort -u | head -40

2. Data flow diagram

DFD element types: external entity (actor/system you do not control), process (your code), data store, data flow, trust boundary. Draw it in Mermaid so it lives in the repo:

flowchart LR
  subgraph Internet[Untrusted: Internet]
    U[User browser]
    S[Stripe]
  end
  subgraph DMZ[Boundary: edge]
    LB[Load balancer / WAF]
  end
  subgraph App[Trusted: app VPC]
    API[API service]
    W[Webhook worker]
    Q[(Job queue)]
    DB[(Postgres: orders, PII)]
  end
  U -- "HTTPS: login, orders (JWT)" --> LB --> API
  API -- "SQL over TLS" --> DB
  S -- "HTTPS webhook (signed)" --> LB --> W
  W --> Q --> API
  API -- "HTTPS: create PaymentIntent" --> S

Label every flow with protocol, data, and authentication. Every arrow crossing a subgraph edge is a trust-boundary crossing and gets the most scrutiny.

3. STRIDE per element

ThreatViolatesApplies toAsk
SpoofingAuthenticationExternal entities, processesCan someone pretend to be this user/service?
TamperingIntegrityFlows, stores, processesCan data be modified in transit, at rest, or in the client?
RepudiationNon-repudiationProcesses, external entitiesCould an actor deny an action because we lack audit evidence?
Information disclosureConfidentialityFlows, stores, processesCan data leak via responses, logs, errors, backups, side channels?
Denial of serviceAvailabilityProcesses, stores, flowsCan someone exhaust CPU, memory, connections, quotas, money?
Elevation of privilegeAuthorizationProcessesCan a lower-privileged actor do something reserved for a higher one?

STRIDE-per-element shortcut: external entities get S and R; data flows get T, I, D; data stores get T, I, D (and R if they hold audit logs); processes get all six.

High-yield threats to check at every boundary crossing:

  • Missing or bypassable authentication on internal endpoints (“it’s inside the VPC”).
  • Object-level authorization (IDOR) and tenant isolation.
  • Webhook/callback spoofing without signature verification and replay window.
  • Secrets in env vars readable by too many processes, or in logs.
  • SSRF from any process that fetches URLs into the trusted zone.
  • Unbounded inputs: file sizes, pagination, regex, batch sizes, LLM tokens.
  • Admin and support tooling with broad data access and weak audit.
  • Third-party compromise: what happens if Stripe/IdP/CDN/npm package is malicious?

4. Existing mitigations

For each threat, look for the control in code or config and cite it (middleware/auth.ts:22 verifies JWT signature and aud). A mitigation you cannot find is “planned” or “missing”, not “existing”.

5. Rank risk

Use a simple, explainable scale; do not pretend to precision.

Likelihood \ ImpactLowMediumHigh
High (unauthenticated, easy, known technique)MediumHighCritical
Medium (needs account or specific condition)LowMediumHigh
Low (needs insider, chained bugs, rare config)LowLowMedium

Impact anchors: High = cross-tenant data, credential/key compromise, payment fraud, full outage. Medium = single-user data, partial degradation. Low = minor info leak.

6. Decide

ResponseWhen
MitigateDefault for High/Critical; add a control and a test
EliminateRemove the feature, data, or flow (often cheapest: stop storing it)
TransferPush to a provider with a contract (hosted payments page, managed IdP)
AcceptLow risk or cost exceeds impact; requires a named approver and review date

7. Output

# Threat model: <feature/service>
**Version / date:** v1, 2026-03-02   **Authors:** ...   **Reviewers:** ...
**Scope:** ...   **Out of scope:** ...

## Assets and actors
...

## Assumptions
1. TLS terminates at LB; traffic inside VPC is plaintext. (Challenge: is that acceptable?)

## Data flow diagram
<mermaid block>

## Threats
| ID | Element / flow | STRIDE | Threat | Existing mitigation | Risk | Response | Owner |
|---|---|---|---|---|---|---|---|
| T1 | Stripe -> Webhook worker | S, T | Forged webhook marks order paid | None found | Critical | Mitigate: verify `Stripe-Signature`, 5-min tolerance | @payments |
| T2 | API -> DB | I | Orders endpoint returns other tenants' rows | tenant_id filter in repo layer (orders.repo.ts:40) | Low | Accept, add regression test | @api |

## Actions
- [ ] T1 verify webhook signatures (owner, due date, ticket)

## Accepted risks
| ID | Rationale | Approver | Review by |

## Validation
- Diagram reviewed against deployed infra on <date>; differences: ...

Gotchas

  • Diagrams drift. Store the model next to the code and update it in the PR that changes a flow or boundary.
  • “Internal” is not a trust level. Model the compromised-internal-service case: what can one popped container reach?
  • Do not stop at the happy path: include admin flows, background jobs, backups, data exports, CI/CD with deploy credentials, and support tooling.
  • Repudiation is the most skipped category; audit logs for money movement and permission changes are cheap and often legally required.
  • LLM features add boundaries: model output is untrusted input to anything it calls. Hand depth to prompt-injection-defense.

Verification

  • Every boundary-crossing flow in the diagram has at least one threat considered or a written reason it has none.
  • Every “existing mitigation” cites a file, config key, or provider setting.
  • Every High/Critical has an owner and a ticket; every accepted risk has an approver.
  • Walk the diagram with someone who operates the system; fix any element they do not recognize before ranking.

About this skill

Written and maintained by the Claude Skills editors to the same editorial standard as every skill in the directory: a selective trigger, a real workflow, known pitfalls and a verification step. First published , last updated . MIT licensed.

esc