Skip to content
StackPractices
intermediate By Mathias Paulenko

Threat Modeling — A Practical Guide for Development Teams

A step-by-step guide to threat modeling: STRIDE, attack trees, data flow diagrams, and integrating security design review into your development process.

Note: This guide follows English-language naming conventions and terminology standards common in international development teams. Examples use English identifiers and comments to maximize compatibility across codebases and tooling.

Overview

Threat modeling is the process of identifying, communicating, and managing security threats in a system before a single line of code is written. By analyzing the architecture and data flows, teams can anticipate attacks and build mitigations into the design. It is one of the most useful security activities because fixing vulnerabilities in design is orders of magnitude cheaper than fixing them in production.

When to Use

  • For alternatives, see Gatekeeper Pattern.

  • You are designing a new system or major feature

  • You are reviewing an existing architecture for security gaps

  • You need to communicate security risks to non-technical stakeholders

  • You are preparing for a security audit or compliance review

The Threat Modeling Process

Step 1: Decompose the Application

Create a Data Flow Diagram (DFD) showing how data moves through the system.

┌─────────┐      ┌─────────┐      ┌─────────┐      ┌─────────┐
│  User   │─────▶│   WAF   │─────▶│   API   │─────▶│   DB    │
│ Browser │      │ / CDN   │      │ Gateway │      │         │
└─────────┘      └─────────┘      └─────────┘      └─────────┘
      │                │                │                │
      │                │                │                │
   External        External         Internal        Internal
   Entity          Process          Process        Data Store
      │                │                │                │
      ▼                ▼                ▼                ▼
   Trust:            Trust:           Trust:          Trust:
   None              Low              High            High

Elements to identify:

  • External entities: Users, third-party systems, browsers
  • Processes: Applications, services, functions
  • Data stores: Databases, caches, file systems
  • Data flows: HTTP, gRPC, message queues, internal API calls
  • Trust boundaries: Where trust levels change (e.g., public internet to VPC)

Step 2: Identify Threats with STRIDE

ThreatDescriptionExample
SpoofingPretending to be someone elseStolen credentials, forged JWT
TamperingModifying data or codeMitM attack, supply chain poison
RepudiationDenying an actionNo audit logs for deletions
Information DisclosureExposing data to unauthorized partiesVerbose error messages, S3 bucket leaks
Denial of ServiceMaking the system unavailableDDoS, resource exhaustion
Elevation of PrivilegeGaining unauthorized accessExploiting a bug to become admin

For each element in the DFD, ask: how could STRIDE apply here?

Step 3: Determine Mitigations

ThreatMitigation
SpoofingMFA, certificate pinning, strong auth
TamperingTLS, code signing, input validation
RepudiationImmutable audit logs, digital signatures
Information DisclosureEncryption, least privilege, error sanitization
Denial of ServiceRate limiting, CDN, auto-scaling
Elevation of PrivilegeRBAC, sandboxing, principle of least privilege

Step 4: Validate and Iterate

  • Review the model with the full team (security, developers, operations)
  • Revisit the model when the architecture changes
  • Track mitigations as engineering tasks in your backlog

Attack Trees

Attack trees decompose a high-level attack goal into sub-goals, helping identify the path of least resistance for attackers.

Goal: Steal customer data
│
├── Compromise application server
│   ├── Exploit known vulnerability (CVE)
│   │   └── Mitigation: Patch within 24h
│   ├── SQL injection
│   │   └── Mitigation: Parameterized queries
│   └── Weak admin password
│       └── Mitigation: Enforce MFA
│
├── Access database directly
│   ├── Exposed database port
│   │   └── Mitigation: Security groups, no public access
│   └── Stolen credentials
│       └── Mitigation: Vault, short-lived credentials
│
└── Insider threat
    └── Mitigation: Audit logging, principle of least privilege

Tools and Templates

ToolPurpose
Microsoft Threat Modeling ToolCreate DFDs and apply STRIDE automatically
OWASP Threat DragonOpen-source threat modeling with team collaboration
PyTMPython-based threat modeling for programmatic generation
Mermaid / Diagrams.netCreate DFDs and attack trees

Integrating into Development

Sprint 0: Architecture Review

Conduct threat modeling during the design phase, before implementation begins.

Definition of Done

  • DFD created and reviewed
  • STRIDE threats identified for each trust boundary
  • Mitigations documented and added to the backlog
  • Security tests defined for each mitigation

Continuous Review

Revisit the threat model when:

  • New integrations or APIs are added
  • Trust boundaries change (e.g., new region, new vendor)
  • A vulnerability is discovered in a similar system

Common Mistakes

  • Threat modeling too late — after code is written, fixes are expensive
  • Only security team participates — developers know the system best
  • Treating the model as a one-time document — architectures evolve; so do threats
  • Ignoring insider threats — not all attackers are external
  • Focusing only on software — social engineering and physical access are valid threats

Troubleshooting

  • Authentication bypass in tests: ensure test users cannot reach production endpoints. Use separate credentials and environments for CI.
  • False positives in scanning tools: tune rules against the risk profile. Distinguish between reachable vulnerabilities and theoretical issues.
  • Secrets appear in logs: configure log filters to redact tokens, passwords, and keys. Audit log sinks for sensitive patterns.
  • CSP breaks legitimate functionality: use report-only mode first, then enforce. Iterate on allowed sources based on real violations.
  • Incident response stalls: run tabletop exercises. Document escalation paths, evidence collection steps, and communication templates in advance.

FAQ

How long does threat modeling take? A focused session for a single service takes 2-4 hours. Complex systems may need multiple sessions.

Do I need a security expert to enable? Helpful but not required. A developer trained in STRIDE can lead the session. External consultants can validate findings.

How do I prioritize threats? Use a risk matrix: likelihood × impact. Address high-likelihood, high-impact threats first. Document accepted risks for low-priority items.

How do I get started with this in an existing project?

Start with a small, isolated part of your codebase. Apply the concepts from this guide to one module or service. Measure the impact, then expand to other areas.

What tools do I need?

The tools mentioned throughout this guide are listed in each section. Most are open-source and widely adopted. Check the related resources for setup instructions.

How do I measure success after implementing this?

Define clear metrics before starting: performance benchmarks, error rates, or maintainability indicators. Compare before and after. Iterate based on the data, not on assumptions.

Advanced Topics

Scenario: Threat Modeling for Payment API

System: Payment API, OAuth2, handles credit cards
Method: STRIDE (Spoofing, Tampering, Repudiation,
  Info Disclosure, Denial of Service, Elevation of Privilege)

Flow diagram:
  Client -> API Gateway -> Auth Service -> Payment Service
                                    -> Vault (secrets)
                                    -> DB (transactions)
                                    -> Stripe API

Identified threats (STRIDE):
  | Category | Threat | Mitigation | Severity |
  |----------|--------|------------|----------|
  | Spoofing | Forged JWT token | Verify signature + expiry | High |
  | Spoofing | Client impersonates another user | Scope validation per user | High |
  | Tampering | Modify amount in request | HMAC signature on payload | High |
  | Tampering | Man-in-the-middle | TLS 1.3 + certificate pinning | Medium |
  | Repudiation | User denies transaction | Immutable audit log + timestamp | High |
  | Info Disclosure | Log of card number | Masking + PCI DSS compliance | Critical |
  | Info Disclosure | Error exposes stack trace | Generic messages in prod | Medium |
  | DoS | Request flood | Rate limiting + WAF | High |
  | DoS | Expensive query without limit | Pagination + query timeout | Medium |
  | EoP | Regular user accesses admin | RBAC + scope validation | High |
  | EoP | Service account with excessive permissions | Least privilege + IAM audit | High |

Prioritization (risk = impact x probability):
  | Threat | Impact | Probability | Risk | Priority |
  |--------|--------|-------------|------|----------|
  | Card logging | Critical | Medium | 8 | 1 |
  | Forged JWT | High | High | 9 | 1 |
  | Amount modification | High | Medium | 6 | 2 |
  | Missing rate limiting | High | High | 9 | 1 |
  | Missing RBAC | High | Low | 3 | 3 |
  | Stack trace exposed | Medium | High | 4 | 3 |

Mitigation plan:
  1. PCI DSS: tokenize cards via Stripe (never store PAN)
  2. JWT: RS256 + expiry 15min + refresh token rotation
  3. HMAC: sign critical payloads (amount, destination account)
  4. Rate limiting: 100 req/min per user, 1000 per IP
  5. RBAC: roles user/admin/super_admin with scope per resource
  6. Audit log: append-only with hash chain (tamper-evident)
  7. Error handling: generic messages, stack trace only in logs
  8. WAF: OWASP rules + custom rules for payment endpoints

Lessons:
  - STRIDE is systematic: it does not skip categories
  - Prioritize by risk, not by intuition
  - PCI DSS: if you touch cards, tokenize everything
  - Immutable audit log is your defense against repudiation
  - Threat model is a living document: update per feature

How often should I update the threat model?

Update it on every significant change: new endpoint, new dependency, architecture change, new sensitive data type. At minimum, review quarterly. If you use CI/CD, add a threat modeling checklist to the PR template for changes affecting auth, payments, or sensitive data.

End of document. Review and update quarterly.

Common Production Pitfalls

  • Treating the guide as a checklist to complete once rather than a practice to evolve.
  • Adopting every recommendation at once instead of starting with one measured change.
  • Skipping the maturity assessment and forcing advanced practices on an unprepared team.
  • Not updating runbooks and on-call expectations as new practices are introduced.
  • Ignoring real incident data when prioritizing which parts of the guide to apply first.
  • Failing to assign an owner who reviews decisions quarterly.
  • Copying examples without adapting them to the team’s actual tooling and constraints.
  • Forgetting to measure outcomes before adding the next improvement.