Skip to main content

Integration: Threat Modeling Workflow

This guide walks through a complete threat modeling workflow — from input through interview, structured output, and diagram generation.

End-to-End Workflow

Step 1: Prepare the Architecture Description

Write a clear description of the system being modeled. Include:

  • Components and their roles
  • Data flows between components
  • Trust boundaries
  • External dependencies
  • Authentication and authorization mechanisms
  • Data classification (what is sensitive)

Example input:

System: Customer Portal API

Components:
- React SPA served from CloudFront
- API Gateway (Kong) handling JWT authentication
- User Service (Node.js, Express) — account management, PostgreSQL
- Payment Service (Java, Spring Boot) — payment processing via Stripe API, PostgreSQL
- Notification Service (Python, FastAPI) — email via SendGrid, reads from SQS queue
- All services in EKS (Kubernetes) in a private VPC
- Redis for session caching
- S3 for document storage with pre-signed URLs

Trust boundaries:
- Public internet (browser to CDN)
- DMZ (CDN, API Gateway)
- Private network (microservices, databases)
- External (Stripe, SendGrid, SQS)

Step 2: Run the Threat Model Interview

Start a conversation with the threat modeling interview prompt as the system prompt.

import anthropic

client = anthropic.Anthropic()

with open("prompts/threat-modeling/03-threat-modeling-interview-opus.md") as f:
interview_prompt = f.read()

messages = []
messages.append({
"role": "user",
"content": "I need to threat model our Customer Portal API. Here is the architecture:\n\n[paste architecture description]"
})

response = client.messages.create(
model="claude-opus-4-6",
max_tokens=4096,
system=interview_prompt,
messages=messages
)

# The model asks its first question — continue the multi-turn conversation
print(response.content[0].text)

The interview typically runs 15-30 questions, covering:

  • Data classification and sensitivity
  • Authentication mechanisms and session management
  • Authorization models and access control
  • Network architecture and trust boundaries
  • Logging, monitoring, and incident response
  • Third-party dependencies and supply chain risks
  • Deployment and infrastructure security

Step 3: Get Structured Output

At the end of the interview, the model produces a structured threat model. Request CycloneDX-formatted output:

Please produce the final threat model in CycloneDX JSON format.

Example output structure:

{
"bomFormat": "CycloneDX",
"specVersion": "1.6",
"serialNumber": "urn:uuid:...",
"version": 1,
"metadata": {
"timestamp": "2026-02-24T00:00:00Z",
"component": {
"type": "application",
"name": "Customer Portal API"
}
},
"vulnerabilities": [
{
"id": "THREAT-001",
"description": "JWT token theft via XSS in React SPA",
"analysis": {
"state": "exploitable",
"detail": "If an attacker achieves XSS in the React frontend, they can steal JWT tokens from localStorage and impersonate the user."
},
"ratings": [
{
"method": "other",
"severity": "high",
"score": 7.5
}
],
"recommendation": "Store JWT tokens in HttpOnly cookies instead of localStorage. Implement Content Security Policy headers."
}
]
}

Step 4: Generate a Diagram

Feed the architecture description to a diagram generator prompt:

with open("prompts/threat-modeling/12-threat-model-diagram-generator-opus.md") as f:
diagram_prompt = f.read()

response = client.messages.create(
model="claude-opus-4-6",
max_tokens=8192,
system=diagram_prompt,
messages=[
{"role": "user", "content": architecture_description}
]
)

diagram_output = response.content[0].text

# Extract the Mermaid diagram from the output
# Save to a .mmd file for rendering
with open("threat-model-diagram.mmd", "w") as f:
f.write(diagram_output)

Example Mermaid output:

Step 5: Render and Export

Render the Mermaid diagram to SVG:

npx @mermaid-js/mermaid-cli -i threat-model-diagram.mmd -o threat-model-diagram.svg

Embed in your repository:

<!-- docs/threat-model.md -->

## Threat Model Diagram

![Threat Model](./threat-model-diagram.svg)

## STRIDE Threat Matrix

| Component | S | T | R | I | D | E |
|-----------|---|---|---|---|---|---|
| API Gateway | JWT spoofing | Token tampering | No request logging | Config exposure | Rate limiting gap | Auth bypass |
| User Service | Session hijack | DB tampering | Missing audit log | PII in logs | Query DoS | IDOR |
| Payment Service | Stripe key theft | Amount tampering | No payment log | Card data exposure | Stripe rate limit | Privilege escalation |

Automation Script

Combine all steps into a single script:

#!/usr/bin/env python3
"""Run a complete threat model workflow from architecture description."""

import anthropic
import json
import sys

def run_threat_model(architecture_path, output_dir):
client = anthropic.Anthropic()

with open(architecture_path) as f:
architecture = f.read()

# Step 1: Generate diagram
with open("prompts/threat-modeling/12-threat-model-diagram-generator-opus.md") as f:
diagram_prompt = f.read()

diagram_response = client.messages.create(
model="claude-opus-4-6",
max_tokens=8192,
system=diagram_prompt,
messages=[{"role": "user", "content": architecture}]
)

with open(f"{output_dir}/diagram.mmd", "w") as f:
f.write(diagram_response.content[0].text)

# Step 2: Generate STRIDE analysis
with open("prompts/threat-modeling/06-stride-api-threat-modeling-opus.md") as f:
stride_prompt = f.read()

stride_response = client.messages.create(
model="claude-opus-4-6",
max_tokens=8192,
system=stride_prompt,
messages=[{"role": "user", "content": architecture}]
)

with open(f"{output_dir}/stride-analysis.md", "w") as f:
f.write(stride_response.content[0].text)

print(f"Outputs written to {output_dir}/")


if __name__ == "__main__":
run_threat_model(sys.argv[1], sys.argv[2])
python threat-model.py docs/architecture.md docs/threat-model/