Model Threats with STRIDE
Learn to model threats with STRIDE step by step in this Security foundations tutorial. Practical, hands-on, with troubleshooting and next steps.
Focus: model threats with stride step by step
You’ve built the feature, wired the API, and deployed it — but have you actually thought about how an attacker will break it? Most teams only discover their vulnerabilities after a breach, when the cost is measured in downtime, leaked data, and lost trust. That’s the pain this lesson solves: teaching you to model threats with STRIDE step by step, a systematic way to find security weaknesses before they become incidents.
By the end of this lesson, you’ll be able to take any system — a web app, a microservice, even a home IoT device — and walk through the STRIDE framework to identify concrete threats, then prioritize fixes. You won’t become a security expert overnight, but you’ll gain the structured mindset that separates reactive developers from proactive ones.
The problem this lesson solves
When you ask a developer “Is your system secure?”, the most common answer is a shrug: “I think so, I used HTTPS.” That’s not threat modeling — that’s hope. The reality is that security issues hide in the details: a forgotten API endpoint, an unvalidated file path, an overly broad CORS policy. Without a checklist, you’ll miss them until someone exploits them.
The core problem: security is not a feature you add at the end; it’s a property you must design for. Random security reviews are like proofreading a novel by reading only the first and last page — you’ll miss most of the plot holes.
Threat modeling is the structured answer. Instead of asking “Is this secure?” (unanswerable), you ask “What could go wrong, and how likely is it?” This shifts the conversation from fear to analysis. STRIDE gives you a repeatable, step-by-step framework to answer that question for any architecture.
But even with a framework, most people still struggle because they don’t know where to start. They stare at a blank diagram and freeze. This lesson gives you a linear, practical method to move from “I have no idea” to “I have a prioritized list of threats.”
Core concept / mental model
Imagine you’re a bank teller. Your job is to process transactions, but you also need to prevent robberies. You wouldn’t just stand there hoping no one robs you — you’d look at the doors, the cameras, the cash drawer. STRIDE is that same mental checklist, but for software.
STRIDE is an acronym for six threat categories, each representing a different way an attacker can violate security:
| Letter | Threat | What it violates | Example in a web app |
|---|---|---|---|
| S | Spoofing | Authenticity | Attacker logs in as another user |
| T | Tampering | Integrity | Attacker modifies a transaction amount |
| R | Repudiation | Non-repudiation | User denies making a purchase |
| I | Information Disclosure | Confidentiality | Attacker reads other users’ private data |
| D | Denial of Service | Availability | Attacker floods the server with requests |
| E | Elevation of Privilege | Authorization | Guest user gains admin rights |
The mental model: every data flow in your system is a highway, and STRIDE is a checkpoint that asks six questions about each highway. You don’t apply STRIDE to the whole system at once — that’s overwhelming. Instead, you break your system into small pieces (components, data flows, trust boundaries) and analyze each one through the six lenses.
Think of STRIDE as a security lens kit. Each lens shows you a different kind of threat. You put on the Spoofing lens, look at your login flow, and ask “Can someone fake this?” Then you switch to the Tampering lens, look at your database writes, and ask “Can someone modify this?” The power is in the systematic repetition.
How it works step by step
Threat modeling with STRIDE is a four-phase process. Follow these steps every time — even for small features. The discipline matters more than the tool.
Phase 1: Decompose the system — Draw a simple diagram of your system: components (web server, database, third-party API), data flows (HTTP requests, SQL queries), and trust boundaries (where data crosses from lower to higher trust).
Phase 2: Apply the STRIDE lens — For each data flow, ask the six STRIDE questions. Use the table above as a cheat sheet. For example, for a login request: can I spoof the user? (S), can someone tamper with the password in transit? (T), can a user deny they logged in? (R), does the response leak session data? (I), can I flood the login endpoint? (D), can a normal user elevate to admin through this flow? (E).
Phase 3: Assess and prioritize — Not all threats are equal. Assign each threat a rough likelihood (Low/Medium/High) and impact (data loss, financial, reputational). Prioritize High/High first. You don’t need to fix everything; you need to fix what matters.
Phase 4: Document and iterate — Write the threats in a table (or a tool like OWASP Threat Dragon). Share with your team. Revisit when the architecture changes.
Step-by-step application for a concrete flow:
- Pick a data flow — e.g., “User submits password change.”
- Draw it — Browser → HTTPS → Web server → Database.
- Identify trust boundaries — Between browser and server (untrusted network), between server and database (trusted internal).
- Apply STRIDE to each boundary — For the untrusted boundary, Spoofing (fake user), Tampering (intercept and change request), Information Disclosure (eavesdrop on password), DoS (flood).
- Log threats — Create a table: Threat description, category, likelihood, impact, mitigation.
- Prioritize — Fix the ones with high likelihood AND high impact.
Pro tip: Don’t model your entire system in one sitting. Break it into “epics” — one payment flow, one user invite flow. Each epic gets its own STRIDE session. Consistency beats perfection.
Hands-on walkthrough
Let’s apply STRIDE to a simplified online store. We’ll model a user adding an item to their cart, a classic flow with multiple attack surfaces. We’ll use Python and Flask to illustrate the components, but the STRIDE analysis is language-agnostic.
Step 1: Decompose the flow
Here’s the data flow in code:
# app.py (simplified)
from flask import Flask, request, session
app = Flask(__name__)
app.secret_key = "dev-key" # in production, use a proper secret
@app.route("/cart/add", methods=["POST"])
def add_to_cart():
user_id = session.get("user_id")
item_id = request.json.get("item_id")
quantity = request.json.get("quantity", 1)
# Simulate DB insert (not real SQL here)
cart_db.insert(user_id, item_id, quantity)
return {"status": "ok"}
if __name__ == "__main__":
app.run(debug=True)
Components: Browser, Flask app, in-memory cart_db. Data flows: HTTP request → app → database. Trust boundaries: browser-to-server (public), server-to-DB (internal).
Step 2: Apply STRIDE
Run this script to generate a STRIDE threat list for this flow:
# stride_analysis.py
threats = []
def add_threat(category, description, likelihood, impact):
threats.append({"category": category, "description": description,
"likelihood": likelihood, "impact": impact})
# Browser -> Server (untrusted)
add_threat("Spoofing", "Attacker steals session cookie and impersonates user", "High", "High")
add_threat("Tampering", "Attacker intercepts request and changes item_id or quantity", "Medium", "Medium")
add_threat("Repudiation", "User claims they never added item; no audit log", "Low", "Low")
add_threat("Information Disclosure", "Response leaks other users' cart contents (IDOR)", "Medium", "High")
add_threat("Denial of Service", "Attacker sends many requests to overload server", "High", "Medium")
add_threat("Elevation of Privilege", "Normal user accesses admin panel through this route", "Low", "Critical")
# Server -> Database (trusted, but still check)
add_threat("Tampering", "SQL injection modifies cart data", "Medium", "Critical")
add_threat("Information Disclosure", "Database dump exposes all users' carts", "Low", "High")
for t in threats:
print(f"{t['category']}: {t['description']} (L:{t['likelihood']}, I:{t['impact']})")
Output (abridged):
Spoofing: Attacker steals session cookie and impersonates user (L:High, I:High)
Tampering: Attacker intercepts request and changes item_id or quantity (L:Medium, I:Medium)
...
Tampering: SQL injection modifies cart data (L:Medium, I:Critical)
Step 3: Prioritize with a risk matrix
Now compute a priority score:
# prioritization.py
threat_list = [
# (description, likelihood_score, impact_score) # 1-5 scale
("Session Hijacking", 4, 5),
("SQL Injection", 3, 5),
("IDOR - View other user's cart", 3, 4),
("Rate limiting bypass", 5, 2),
]
for desc, lik, imp in threat_list:
score = lik * imp
priority = "HIGH" if score >= 15 else "MEDIUM" if score >= 9 else "LOW"
print(f"{desc}: score={score} -> {priority}")
Output:
Session Hijacking: score=20 -> HIGH
SQL Injection: score=15 -> HIGH
IDOR - View other user's cart: score=12 -> MEDIUM
Rate limiting bypass: score=10 -> MEDIUM
Now you have a concrete list to fix. The high-priority items (session security, parameterized queries) should go into your backlog before the medium ones.
Compare options / when to choose what
STRIDE is not the only threat modeling method. Depending on your context, other frameworks may be more suitable. Here’s a comparison:
| Method | Best for | Pros | Cons |
|---|---|---|---|
| STRIDE | Developer-led, code-level analysis | Systematic, easy to remember, integrates with OWASP | Can be time-consuming for large systems |
| DREAD | Risk rating (integrates with STRIDE) | Quantifies threats | Subjective scores, less common now |
| Attack trees | Adversarial thinking, root-cause analysis | Visual, explores attack paths | Harder to apply step by step |
| LINDUN | Privacy-focused systems | Addresses privacy alongside security | Niche, less known |
| Misuse cases | Agile teams, early design | Pair with user stories | Less detailed than STRIDE |
When to choose what: - Use STRIDE for most development work — it’s the best all-rounder for modeling threats step by step. - Add DREAD when you need a numeric risk score for each threat. - Choose Attack trees when you have a known high-risk component (e.g., a login system) and want to explore all attack vectors. - Use LINDUN if you handle sensitive personal data and need to model privacy threats (GDPR). - Pick Misuse cases if you’re in an agile environment and want to integrate security into user stories.
The key is to use STRIDE as your baseline and add other methods for specific concerns. Most teams get 80% of the value from STRIDE alone.
Troubleshooting & edge cases
Even with STRIDE, you’ll hit common issues. Here’s how to handle them:
1. “I don’t know where to start — my system is too big.”
- Fix: Use the “epic” precision. Break your system into user stories (e.g., “As a user, I log in”). Model each story separately. Start with the stories that handle sensitive data or money.
2. “My threat list is overwhelming — 50 threats!”
- Most threats are Low/Low — that’s normal. Filter by the priority score (as in the example). Focus only on High/High and Medium/Medium. You can revisit others later.
3. “I missed a critical threat because I didn’t think of it.”
- That happens. STRIDE is a checklist, not a magic wand. Use OWASP’s Threat and Mitigation Table as a supplement. Also, do a “what if” session with a colleague — two brains catch more.
4. “I found the threat, but I don’t know how to fix it.”
- STRIDE identifies threats, not solutions. For each threat, consult OWASP Cheat Sheets (e.g., for SQL injection, use parameterized queries; for spoofing, use strong authentication). The fix is separate from the modeling.
5. “The trust boundary when to draw it?”
- If data passes between two components with different security levels (e.g., from public internet to internal server), that’s a boundary. When in doubt, draw it — more boundaries mean more thorough analysis.
What you learned & what's next
In this lesson, you learned the core idea behind model threats with STRIDE step by step: a systematic method to identify security vulnerabilities by applying six threat categories to each data flow in your system. You practiced with a Python Flask app, generated a threat list, and prioritized fixes using a risk matrix. You also saw how STRIDE compares to other methods and how to troubleshoot common pitfalls.
You now have the skills to complete a practical exercise for model threats with STRIDE step by step — you can apply it to your own projects right now.
In the next lesson, you’ll learn about the CIA triad in depth — how to align your threat mitigations with the core security objectives of Confidentiality, Integrity, and Availability. This will help you choose the right controls to address the threats you’ve identified.
Start by evaluating a simple feature you built recently — spend 15 minutes drawing its data flow and applying STRIDE. The experience is invaluable.
Practice recap
Run the prioritization script on your own project. Pick a simple feature, write down the data flow, apply STRIDE, and list the top 5 threats you’d fix first. Then, for the highest-priority threat, look up on OWASP and implement at least one mitigation. This practical exercise will train your security intuition.
Common mistakes
- Applying STRIDE to the whole system at once leads to analysis paralysis; decompose into smaller flows first.
- Treating STRIDE as a one-time checkbox instead of an iterative process that repeats when the architecture changes.
- Ignoring low-likelihood threats; sometimes a low-risk threat becomes critical when it compounds with others.
- Forgetting to document threats and mitigations; without a record, the analysis is lost and cannot be revisited.
- Confusing the impact of a threat with its fix; STRIDE only identifies, it doesn't dictate the solution.
Variations
- Use DREAD (Damage, Reproducibility, Exploitability, Affected users, Discoverability) to quantify each STRIDE threat for easier prioritization.
- Adopt automated threat modeling tools like OWASP Threat Dragon or Microsoft Threat Modeling Tool to generate STRIDE lists from diagrams.
- Pair STRIDE with attack trees for high-risk components to explore attack paths in more depth than the linear checklist.
Real-world use cases
- Modeling a payment gateway flow with STRIDE to identify spoofing and tampering risks before PCI compliance audit.
- Applying STRIDE to a multi-tenant SaaS to detect information disclosure threats like IDOR between tenant data.
- Using STRIDE to assess a new microservice that handles user uploads, spotting DoS and elevation of privilege risks early.
Key takeaways
- STRIDE - six threat categories, one lens at a time.
- Decompose your system first, then apply STRIDE to each data flow.
- Prioritize threats using likelihood × impact, not raw count.
- Document every threat and mitigation to make the analysis reusable.
- STRIDE works best iterating with architecture changes.
- Use OWASP cheat sheets to turn identified threats into concrete fixes.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.