# A practical threat-modeling guide [2026 edition]: crushing vulnerabilities at the 'design stage' with STRIDE and data flow diagrams

> A practical guide to threat modeling for building security into the design stage. It explains, with real code faithful to official information: the Threat Modeling Manifesto's four questions, STRIDE's six categories, how to draw a data flow diagram and trust boundaries, and how to manage threats 'as code' and continuously verify them in CI.

- Published: 2026-06-28
- Author: 友田 陽大
- Tags: セキュリティ, 脅威モデリング, STRIDE, セキュア設計, セキュリティエンジニア
- URL: https://tomodahinata.com/en/blog/threat-modeling-stride-data-flow-diagram-secure-design-practical-guide
- Category: Security engineering & career
- Pillar guide: https://tomodahinata.com/en/blog/security-engineer-how-to-become-roadmap-skills-certification-guide

## Key points

- Threat modeling is the design activity of 'thinking about what can go wrong before you write code.' The cheapest place to crush a vulnerability is the design stage, an order of magnitude away from the post-release discovery/fix cost (shift left).
- The Threat Modeling Manifesto's four questions are the starting point of everything: 'what are we working on / what can go wrong / what are we going to do about it / did we do a good enough job.' More than a difficult tool, running these questions as a team is the essence.
- STRIDE is the six categories for exhaustively enumerating threats (spoofing, tampering, repudiation, information disclosure, denial of service, elevation of privilege). Applying STRIDE to each element of the data flow diagram structurally reduces oversights.
- Drawing trust boundaries is the core. Where a boundary is crossed — user input, external APIs, another service — is the entrance for threats. Once the boundary is visible, where to validate/authorize becomes visible.
- Don't end the threat model as a 'document'; manage it as 'code.' Hold the threat registry in YAML, verify the presence of mitigations with tests, and continuously keep it current in CI, and you prevent the divergence of design and implementation.

---

Security defects are **cheaper the earlier you find them** — this is an industry iron rule. If a vulnerability is found after production release, the cost is unlimited: investigation, fix, redeploy, and in some cases responding to information leakage. On the other hand, **find it on a diagram at the design stage and it's just an erase with an eraser.**

The systematic method for this "building security in at the design stage" is **threat modeling.** This article, rather than how to use abstruse tools, explains **a thinking type a team can run right away**, faithful to official information (the [Threat Modeling Manifesto](https://www.threatmodelingmanifesto.org/), Microsoft's [STRIDE](https://learn.microsoft.com/en-us/azure/security/develop/threat-modeling-tool-threats), [OWASP Threat Modeling](https://owasp.org/www-community/Threat_Modeling)), and finally goes all the way to the implementation of **managing threats "as code."**

> **The positioning of this article:** of a security engineer's core skills, this deeply explores the **"Identify"** in NIST CSF 2.0 terms — the ability to surface risk at the design stage. For the roadmap of the role overall, see [how to become a security engineer](/blog/security-engineer-how-to-become-roadmap-skills-certification-guide), and for the technique of crushing the surfaced threats in implementation, [secure-coding practices](/blog/secure-coding-practices-nist-ssdf-owasp-asvs-engineer-guide).

---

## 0. What threat modeling is — just answer four questions

When you hear threat modeling, you tend to imagine a dedicated tool or abstruse notation, but the essence is answering, as a team, the **four questions** the [Threat Modeling Manifesto](https://www.threatmodelingmanifesto.org/) raises.

1. **What are we working on?** — diagram the target system.
2. **What can go wrong?** — surface the threats.
3. **What are we going to do about it?** — decide on mitigations.
4. **Did we do a good enough job?** — verify.

Running these four questions for an hour in a design-review setting is already valuable. The Manifesto says — **"a valuable model over a perfect model," "people and collaboration over checklists."** Threat modeling isn't a "ritual" but **a collaborative activity to think one level deeper about the design.**

---

## 1. STRIDE — the six categories for exhaustively enumerating threats

Listing "what can go wrong" by "feel" will surely leave gaps. So use **STRIDE**, systematized by Microsoft. It divides threats into six categories, each corresponding to **which security property it breaks.**

| STRIDE | Threat | Property broken | Example |
|---|---|---|---|
| **S**poofing | Spoofing | Authentication | Log in by impersonating someone else |
| **T**ampering | Tampering | Integrity | Rewrite a request or stored data |
| **R**epudiation | Repudiation | Non-repudiation | Wriggle out with "I didn't do it" (poor logs) |
| **I**nformation Disclosure | Information disclosure | Confidentiality | Peek at someone else's data |
| **D**enial of Service | Denial of service | Availability | Stop the service with mass requests |
| **E**levation of Privilege | Privilege escalation | Authorization | A general user gains admin privileges |

STRIDE's strength is that you can **mechanically ask the six "is there spoofing for this element? tampering? …"** Exhaustiveness beats person-dependent intuition.

---

## 2. Draw a data flow diagram (DFD) and trust boundaries

The best tool to share "what we're working on" is a **Data Flow Diagram (DFD).** More than perfect notation, what matters is seeing **where data flows from and to, and where the 'premise of trust' changes.**

The minimal vocabulary is just this.

- **External Entity**: users, external APIs (which we don't control)
- **Process**: API servers, functions (our code)
- **Data Store**: DB, cache, files
- **Data Flow**: data flowing between elements (arrows)
- **Trust Boundary**: the line where the trust level changes (most important)

```text
        ┌─────────────[ 信頼境界 ]─────────────┐
            （境界の外＝信頼できない）

 [ユーザー] ──HTTPリクエスト──▶ │ [APIサーバー] ──SQL──▶ [DB]
  外部実体                       │   プロセス              データストア
                               │       │
 [外部決済API] ◀──HTTPS────────  │       └──ログ──▶ [ログ基盤]
  外部実体                       └──────────────────────────┘
```

**The trust boundary is the very heart of threat modeling.** Data flows that cross the boundary — user input, external-API responses, calls from another microservice — are **all "the moment something untrusted enters the inside."** This coincides with where validation, authentication, and authorization should take effect. Once the boundary is visible on the diagram, "where to protect" becomes self-evident.

---

## 3. STRIDE × DFD — concretely enumerate threats

Apply STRIDE's six categories to each element of the DFD. For example, about the "user → API server" data flow (crossing the boundary):

| Element | STRIDE | Assumed threat | Mitigation |
|---|---|---|---|
| User authentication | **S**poofing | Impersonation via a weak password / token theft | MFA, [strong authentication](/blog/auth-platform-selection-2026-cognito-auth0-clerk-supabase), short-lived tokens |
| Request body | **T**ampering | Parameter tampering (amount, ID) | [Input validation at the boundary](/blog/secure-coding-practices-nist-ssdf-owasp-asvs-engineer-guide), signing |
| Recording of operations | **R**epudiation | Denying with "I didn't order" | [Tamper-resistant audit logs](/blog/security-logging-detection-engineering-sigma-mitre-attack-siem-guide) |
| Data-retrieval API | **I**nformation Disclosure | Viewing others' data via IDOR | [Server-side authorization](/blog/nextjs-supabase-idor-broken-authorization-rls-detection-guide), RLS |
| Public endpoint | **D**enial of Service | Exhaustion via mass requests | [Rate limiting](/blog/nextjs-serverless-rate-limiting-vercel-guide), timeouts |
| Permission check | **E**levation of Privilege | A general user hits the admin API | Least privilege, server-side role verification |

In this way, just **filling in the "element × STRIDE" matrix** makes the threat enumeration astonishingly exhaustive. You don't need to crush everything perfectly. **Being "aware of it" is decisively more important than not being aware.**

---

## 4. Manage the threat model "as code"

The biggest reason threat modeling becomes a formality is **"writing it in a document once and letting it rot as-is."** The design keeps changing, but the diagram fossilizes as a PNG somewhere on a wiki. The best way to prevent this is to **manage the threat model as code, in the repository** (Threat Modeling as Code).

First, hold the threat registry as **typed structured data.**

```yaml
# threat-model.yaml — 脅威レジストリ（リポジトリで版管理する）
threats:
  - id: T-001
    component: "注文取得API"
    stride: InformationDisclosure
    description: "URLのIDを改ざんし、他人の注文を閲覧できる（IDOR）"
    risk: high          # high | medium | low（可能性 × 影響）
    mitigation: "サーバー側で所有者条件をクエリに焼き込み、RLSで多層防御する"
    mitigated: true     # 緩和策が実装済みか
  - id: T-002
    component: "ログインAPI"
    stride: Spoofing
    description: "総当たりでパスワードを推測される"
    risk: high
    mitigation: "レート制限 + アカウントロック + 漏えいパスワードのブロックリスト照合"
    mitigated: true
  - id: T-003
    component: "管理ダッシュボード"
    stride: ElevationOfPrivilege
    description: "一般ユーザーが管理APIを直接叩いて権限昇格する"
    risk: high
    mitigation: "全管理APIでサーバー側ロール検証を必須化する"
    mitigated: false    # ← まだ未対応
```

Next, write a verification that **"if a high-risk threat has no mitigation / unimplemented, fail CI."** This makes the threat model a "living contract."

```ts
// verify-threat-model.ts — 高リスクの未緩和脅威があればCIを落とす（設計と実装の乖離を防ぐ）。
import { readFileSync } from "node:fs";
import { parse } from "yaml";
import { z } from "zod";

// ① スキーマで脅威モデルを検証（型の不正・記入漏れを起動時に弾く）。
const ThreatSchema = z.object({
  id: z.string().regex(/^T-\d{3}$/),
  component: z.string().min(1),
  stride: z.enum([
    "Spoofing", "Tampering", "Repudiation",
    "InformationDisclosure", "DenialOfService", "ElevationOfPrivilege",
  ]),
  description: z.string().min(1),
  risk: z.enum(["high", "medium", "low"]),
  mitigation: z.string().min(1),
  mitigated: z.boolean(),
});
const ModelSchema = z.object({ threats: z.array(ThreatSchema) });

function verify(path: string): number {
  const model = ModelSchema.parse(parse(readFileSync(path, "utf8")));

  // ② 不変条件：高リスクの脅威は、必ず緩和策が実装済みでなければならない。
  const unmitigated = model.threats.filter((t) => t.risk === "high" && !t.mitigated);

  if (unmitigated.length > 0) {
    console.error("❌ 高リスクなのに未緩和の脅威があります:");
    for (const t of unmitigated) console.error(`  - ${t.id} (${t.component}): ${t.description}`);
    return 1; // CIを失敗させる
  }
  console.log(`✅ ${model.threats.length} 件の脅威すべてに緩和策が実装済みです。`);
  return 0;
}

process.exit(verify("threat-model.yaml"));
```

Place this script in CI and you can **mechanically detect the divergence between "threats raised in design" and "implemented mitigations."** The threat model changes from a "rotting document" into an "unbreakable contract" — this is a security-engineer-like design practice. The thinking on type-safe boundary validation connects to [secure-coding practices](/blog/secure-coding-practices-nist-ssdf-owasp-asvs-engineer-guide).

---

## 5. Prioritizing mitigations — don't try to protect everything

Even if you raise 100 threats, resources are finite. Prioritize by **risk = likelihood × impact.**

| | Impact: large | Impact: small |
|---|---|---|
| **Likelihood: high** | Mitigate as top priority | Mitigate early |
| **Likelihood: low** | Mitigate or accept (record required) | Accept (record only) |

What's important is that **"acceptance" is also a legitimate option.** You can't zero every risk. A state where you can record "this risk is accepted, with a reason" is far healthier than unwittingly leaving it. This is also a decision that management should be responsible for, and the [METI Cybersecurity Management Guidelines](https://www.meti.go.jp/policy/netsecurity/mng_guide.html) also position grasping risk and decision-making as a management responsibility.

---

## 6. When and how much to do it

Threat modeling isn't "do it once and you're done."

- **When designing a new feature**: the most cost-effective. Build 30 minutes to 1 hour of threat modeling into the design review.
- **When the architecture changes**: when the trust boundary moves (new external integration, a change of authentication method, etc.).
- **Periodically**: review the existing model, e.g., once a quarter.

"Light, frequent" is the principle. Rather than doing heavy threat modeling once a year, **continuously running lightweight threat modeling per feature** keeps up with change and takes root in the team as a culture.

---

## 7. Frequently asked questions (FAQ)

**Q. Is threat modeling needed even for a small team / solo development?**
A. It is. Rather, the fewer the people, the greater the value of preventing rework at the design stage. No dedicated tool is needed. You can start by drawing a DFD on a whiteboard and asking STRIDE's six items.

**Q. Should I use a dedicated tool?**
A. Not at first. There's the [Microsoft Threat Modeling Tool](https://learn.microsoft.com/en-us/azure/security/develop/threat-modeling-tool) and OWASP Threat Dragon, etc., but the essence is the thinking of "the four questions" and "STRIDE × DFD." Use tools once you're accustomed.

**Q. What's the difference from methods other than STRIDE (PASTA, LINDDUN, etc.)?**
A. STRIDE has the lowest learning cost and is general-purpose. There are purpose-specific methods like LINDDUN for privacy focus and PASTA for risk-driven, but the royal road is to **first get the type into your body with STRIDE.**

**Q. What's the difference from vulnerability assessment (penetration testing)?**
A. Threat modeling is the "preventive" activity of surfacing threats **at the design stage**, and assessment is the "discovery" activity of searching for vulnerabilities **after implementation.** They're two wheels. For how to do assessment, see [web-app vulnerability assessment](/blog/web-application-vulnerability-assessment-owasp-zap-sast-dast-guide), and for the attacker's viewpoint, [white-hat hacker introduction](/blog/white-hat-hacker-ethical-hacker-how-to-become-certification-roadmap-guide).

**Q. Doesn't it slow down development?**
A. In the short term, design time increases. But threats crushed at the design stage are an order of magnitude cheaper than the post-release incident-response cost ([response per NIST 800-61](/blog/incident-response-nist-800-61r3-csirt-runbook-playbook-production-guide)). Overall development speed actually rises.

---

## 8. Conclusion

Threat modeling is, not special talent or an expensive tool, **a collaborative activity to think one level deeper about the design.**

- **Run the four questions.** What are we working on / what can go wrong / what to do / did we do a good enough job.
- **Be exhaustive with STRIDE × DFD.** Draw trust boundaries and apply the six categories to each element. Beat intuition with exhaustiveness.
- **Manage it as code.** Hold the threat registry in YAML, verify the presence of mitigations in CI, and prevent the divergence of design and implementation.
- **Prioritize, and record acceptance too.** You can't protect everything. Being aware is far healthier than leaving it.
- **Light, frequent.** Keep running it per feature and let it take root as a culture.

Whether you can build security in at the design stage most greatly affects a product's safety. "Building fast" and "building safely" can be reconciled in the first 30 minutes of design — that's the essence of threat modeling. If you want to build threat modeling into your product's design review, or take inventory of the "vertical risks" of an existing design once, feel free to consult me.

---

### References (official primary sources)

- Methods: [Threat Modeling Manifesto](https://www.threatmodelingmanifesto.org/) / [OWASP Threat Modeling](https://owasp.org/www-community/Threat_Modeling) / [OWASP Threat Modeling Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Threat_Modeling_Cheat_Sheet.html)
- STRIDE: [Microsoft — Threat Modeling Tool threats (STRIDE)](https://learn.microsoft.com/en-us/azure/security/develop/threat-modeling-tool-threats)
- Management: [METI Cybersecurity Management Guidelines](https://www.meti.go.jp/policy/netsecurity/mng_guide.html)
