---
title: "Threat Modeling for Developers: STRIDE, Attack Surfaces, Data Flow Diagrams, and Prioritization"
description: "Practical threat modeling that developers can actually use — identifying attack surfaces, building data flow diagrams, applying STRIDE to find threats, scoring risks, and integrating threat modeling into the development workflow."
url: https://agent-zone.ai/knowledge/security/threat-modeling/
section: knowledge
date: 2026-02-22
categories: ["security"]
tags: ["threat-modeling","stride","attack-surface","security-design","risk-assessment","sdl"]
skills: ["threat-modeling","attack-surface-analysis","risk-assessment","security-architecture"]
tools: ["draw-io","owasp-threat-dragon","microsoft-threat-modeling-tool"]
levels: ["intermediate"]
word_count: 1619
formats:
  json: https://agent-zone.ai/knowledge/security/threat-modeling/index.json
  html: https://agent-zone.ai/knowledge/security/threat-modeling/?format=html
  api: https://api.agent-zone.ai/api/v1/knowledge/search?q=Threat+Modeling+for+Developers%3A+STRIDE%2C+Attack+Surfaces%2C+Data+Flow+Diagrams%2C+and+Prioritization
---


# Threat Modeling for Developers

Threat modeling is the practice of systematically identifying what can go wrong in a system before it goes wrong. It is not a security team activity that happens once. It is a design activity that happens every time the architecture changes.

The output of threat modeling is not a report that sits in a wiki. It is a prioritized list of threats that becomes security requirements in the backlog.

## When to Threat Model

- **Before building a new service or feature.** You are making design decisions. Threat modeling informs those decisions.
- **When adding a new external integration.** Every external system is a trust boundary.
- **When changing authentication or authorization.** These are high-impact areas where mistakes have outsized consequences.
- **When handling new categories of data.** PII, financial data, health data, credentials — each has different risk profiles and regulatory requirements.
- **During architecture reviews.** If the architecture is changing, the threat landscape is changing.

You do not need to threat model every bug fix or CSS change.

## Step 1: Define What You Are Modeling

Scope the exercise. Threat modeling the entire company is useless. Threat modeling "the payment processing flow" is actionable.

Start with:
- **What does the system do?** One paragraph.
- **Who are the users?** Human users, API clients, agents, internal services.
- **What data does it handle?** Classify by sensitivity: public, internal, confidential, restricted.
- **What are the deployment boundaries?** Where does it run? What infrastructure does it depend on?

Example:

```
System: Order Processing Service
Function: Accepts orders from the web frontend, validates payment via
          Stripe API, stores order in PostgreSQL, sends confirmation
          via email service.
Users: Authenticated customers, admin dashboard users, internal
       fulfillment service.
Data: Customer PII (name, email, address), payment tokens (not full
      card numbers), order history.
Deployment: Kubernetes cluster, AWS us-east-1, accessed via ALB.
```

## Step 2: Draw the Data Flow Diagram

A data flow diagram (DFD) maps how data moves through the system. It has four elements:

- **External entities** — Users, browsers, external APIs, third-party services. Represented as rectangles.
- **Processes** — Your code, services, functions. Represented as circles.
- **Data stores** — Databases, caches, file systems, message queues. Represented as parallel lines.
- **Data flows** — Arrows showing data movement between elements. Label with what data flows and the protocol.

```
┌──────────┐    HTTPS/JSON     ┌─────────────┐    gRPC/mTLS     ┌──────────────┐
│ Customer  │──────────────────→│  API Gateway │────────────────→│ Order Service │
│ (browser) │                   │              │                  │              │
└──────────┘                   └──────────────┘                  └──────┬───────┘
                                                                        │
                                                         ┌──────────────┼──────────────┐
                                                         │              │              │
                                                         ▼              ▼              ▼
                                                   ┌──────────┐  ┌──────────┐  ┌──────────┐
                                                   │ PostgreSQL│  │ Stripe   │  │ Email    │
                                                   │ (orders,  │  │ API      │  │ Service  │
                                                   │  PII)     │  │ (external│  │ (internal│
                                                   └──────────┘  └──────────┘  └──────────┘
```

### Trust Boundaries

Draw dashed lines where trust changes:

```
╔═══════════════════════════════════════════════════════════╗
║ Internet (untrusted)                                      ║
║  ┌──────────┐                                             ║
║  │ Customer  │                                            ║
║  └─────┬────┘                                             ║
╠════════╪══════════════════════════════════════════════════╣
║ DMZ    │                                                  ║
║        ▼                                                  ║
║  ┌──────────┐                                             ║
║  │ API GW   │                                             ║
║  └─────┬────┘                                             ║
╠════════╪══════════════════════════════════════════════════╣
║ Internal cluster                                          ║
║        ▼                                                  ║
║  ┌──────────┐    ┌──────────┐    ┌──────────┐            ║
║  │ Order Svc│───→│ Postgres │    │ Email Svc│            ║
║  └─────┬────┘    └──────────┘    └──────────┘            ║
╠════════╪══════════════════════════════════════════════════╣
║ External APIs                                             ║
║        ▼                                                  ║
║  ┌──────────┐                                             ║
║  │ Stripe   │                                             ║
║  └──────────┘                                             ║
╚═══════════════════════════════════════════════════════════╝
```

Every trust boundary crossing is a place where threats concentrate. Data crossing a boundary needs authentication, authorization, encryption, and validation.

## Step 3: Identify Threats with STRIDE

STRIDE is a mnemonic for six categories of threats. Walk through each data flow and ask: "Can this be exploited through any of these categories?"

| Category | Question | Example |
|---|---|---|
| **S**poofing | Can someone pretend to be someone else? | Forged auth token, stolen API key, DNS spoofing |
| **T**ampering | Can someone modify data in transit or at rest? | Man-in-the-middle on unencrypted traffic, SQL injection modifying records |
| **R**epudiation | Can someone deny they performed an action? | Missing audit logs, no transaction receipts |
| **I**nformation Disclosure | Can someone access data they should not? | Database query returns extra fields, error messages leak internals, logs contain PII |
| **D**enial of Service | Can someone make the system unavailable? | Unbounded query, no rate limiting, resource exhaustion |
| **E**levation of Privilege | Can someone gain permissions they should not have? | BOLA (accessing other users' data), mass assignment, JWT algorithm confusion |

### Applying STRIDE to the Order Service Example

Walk each data flow across each trust boundary:

**Customer → API Gateway (Internet → DMZ)**

| Threat | Category | Description |
|---|---|---|
| T1 | Spoofing | Attacker uses stolen session cookie to place orders as another customer |
| T2 | Tampering | Attacker modifies order total in the request body |
| T3 | DoS | Attacker floods the order endpoint with requests |
| T4 | Elevation | Attacker changes user ID in the request to access another customer's account |

**API Gateway → Order Service (DMZ → Internal)**

| Threat | Category | Description |
|---|---|---|
| T5 | Spoofing | Compromised gateway sends requests with forged identity headers |
| T6 | Information Disclosure | Gateway logs contain full request bodies with customer PII |
| T7 | Tampering | If traffic is not encrypted, a network-level attacker can modify requests |

**Order Service → PostgreSQL (Internal → Data Store)**

| Threat | Category | Description |
|---|---|---|
| T8 | Tampering | SQL injection allows attacker to modify or delete order records |
| T9 | Information Disclosure | Over-broad database credentials allow Order Service to read tables it does not need |
| T10 | Repudiation | No audit trail for who modified order records |

**Order Service → Stripe API (Internal → External)**

| Threat | Category | Description |
|---|---|---|
| T11 | Spoofing | Stripe webhook callback is not verified — attacker sends fake payment confirmations |
| T12 | Information Disclosure | Stripe API key logged in error messages or debug output |
| T13 | DoS | Stripe rate limits our requests, causing order failures |

## Step 4: Assess Risk

Not all threats are equal. Score each threat to prioritize mitigation.

### DREAD Scoring

Rate each factor 1-3 (low-medium-high):

| Factor | Question |
|---|---|
| **D**amage | How bad is the impact if exploited? |
| **R**eproducibility | How easy is it to reproduce? |
| **E**xploitability | How much skill/effort to exploit? |
| **A**ffected users | How many users are impacted? |
| **D**iscoverability | How easy is it to find the vulnerability? |

Example scoring:

| Threat | D | R | E | A | D | Total | Priority |
|---|---|---|---|---|---|---|---|
| T1: Stolen session | 3 | 2 | 2 | 1 | 2 | 10 | High |
| T2: Modified order total | 3 | 3 | 2 | 1 | 2 | 11 | High |
| T4: BOLA via user ID | 3 | 3 | 3 | 3 | 3 | 15 | Critical |
| T8: SQL injection | 3 | 3 | 2 | 3 | 2 | 13 | Critical |
| T11: Fake webhook | 3 | 2 | 2 | 3 | 2 | 12 | High |
| T6: PII in logs | 2 | 3 | 1 | 3 | 1 | 10 | High |
| T3: Order endpoint DoS | 2 | 3 | 3 | 3 | 3 | 14 | Critical |
| T10: No audit trail | 1 | 3 | 1 | 1 | 1 | 7 | Medium |

### Risk = Likelihood x Impact

A simpler alternative to DREAD for fast triage:

```
           │ Low Impact │ Med Impact │ High Impact
───────────┼────────────┼────────────┼────────────
High Likl. │ Medium     │ High       │ Critical
Med Likl.  │ Low        │ Medium     │ High
Low Likl.  │ Accept     │ Low        │ Medium
```

## Step 5: Define Mitigations

For each high-priority threat, define a concrete mitigation that becomes a backlog item:

| Threat | Mitigation | Implementation |
|---|---|---|
| T4: BOLA | Derive user ID from JWT, never from request path | Code change in order handler |
| T8: SQL injection | Use parameterized queries everywhere | Code review + static analysis |
| T3: DoS | Rate limit order endpoint to 10/min per user | API gateway configuration |
| T2: Modified total | Recalculate total server-side, ignore client-provided total | Code change in order validation |
| T11: Fake webhook | Verify Stripe webhook signature on every callback | Code change in webhook handler |
| T1: Stolen session | Short session TTL (15 min), re-auth for payment | Auth configuration change |
| T6: PII in logs | Redact PII fields in logging middleware | Middleware change |

Each mitigation is specific, implementable, and testable. "Improve security" is not a mitigation. "Verify Stripe webhook signatures using `stripe.webhooks.constructEvent()`" is.

## Step 6: Document and Maintain

A threat model is a living document. Store it alongside the code:

```
docs/
  threat-models/
    order-service.md
    payment-integration.md
    user-authentication.md
```

Each document should contain:
1. System description and scope
2. Data flow diagram
3. Trust boundaries
4. Threat table (STRIDE analysis)
5. Risk scores
6. Mitigations with status (implemented / planned / accepted risk)

Review threat models when:
- The architecture changes.
- New data types are introduced.
- New integrations are added.
- A security incident reveals a missed threat.

## Lightweight Threat Modeling in Practice

Full STRIDE analysis on every feature is not realistic. Use a lightweight approach for day-to-day development:

### Four Questions (Adam Shostack's Framework)

For every design document or PR that changes architecture:

1. **What are we building?** (DFD or even a paragraph)
2. **What can go wrong?** (brainstorm threats)
3. **What are we going to do about it?** (mitigations)
4. **Did we do a good enough job?** (review)

### PR Security Checklist

Add to your PR template:

```markdown
## Security Considerations
- [ ] Does this change handle user input? If yes, is it validated?
- [ ] Does this change cross a trust boundary? If yes, is it authenticated and authorized?
- [ ] Does this change handle sensitive data? If yes, is it encrypted and not logged?
- [ ] Does this change introduce a new external dependency? If yes, is it pinned and verified?
- [ ] Could this change be abused at scale? If yes, are there rate limits?
```

Most PRs check "no" on all items in seconds. The ones that check "yes" trigger a focused threat discussion.

## Common Mistakes

1. **Threat modeling after the system is built.** By then, architectural decisions are locked in. Threat model during design, when changes are cheap.
2. **Listing threats without mitigations.** A threat list without mitigations is anxiety without action. Every threat above the risk threshold needs a concrete mitigation plan with an owner.
3. **Scoring all threats as "critical" to be safe.** If everything is critical, nothing is. Honest scoring lets you prioritize. Some risks are genuinely low and can be accepted.
4. **Not involving developers.** Security teams doing threat modeling in isolation produce documents nobody reads. Developers know the system best and should lead the threat modeling with security guidance.
5. **Treating threat models as one-time documents.** A threat model from last year does not cover this year's integrations. Keep threat models alive alongside the code they describe.

