Threat Modeling
Learn to spot, score, and fix security risks fast by building a lightweight threat model that keeps your systems safe without slowing delivery.
If you're operating at the Staff+ level, you have to make the system safe to ship quickly and scale confidently. That means anticipating what could go wrong before it hits production and costs the company trust, data, or downtime.
And guess what? The security team can’t be everywhere. You are the front line—and you’re expected to model risk, bake in controls early, and guide your team in doing the same.
The ability to run a 20-minute threat model can:
Flag high-risk features before they ship
Reduce security review time
Improve your incident response posture
Build trust with legal, compliance, and execs
Let’s make this skill second nature.
Threat modeling
A threat model is a structured way to ask what could go wrong with a system, and how severe it would be.
In 20 minutes, you can identify the big risks, suggest simple fixes, and write them down so the whole team can ship safely.
The 20-minute threat model
If you can’t answer “yes” to all of these questions:
Can you flip a stop switch for your riskiest feature?
Are all access decisions logged in one place?
Would a leaked secret fail the build?
Can you sketch where PII sits and why?
...then threat modeling will get you there.
Let’s break it down into 4 steps.
1. Map the system (5 min)
Sketch the flow for your feature (e.g., customer data export). Mark the trust boundaries where data or identity context changes (browser↔API, API↔DB, service↔third-party).
Take note of:
Where identity is carried (cookies/tokens).
Where sensitive data (PII) is stored or passes through.
Who is allowed to trigger the action?
The output is a high-level diagram and a short list of assets (e.g., “access tokens, customer emails, CSV download link, admin role”).
2. Name the threats (7 min)
One lightweight approach is STRIDE:
Spoofing (pretending to be someone else). For example, a replayed JSON Web Token (JWT) lets an attacker export another user’s data.
Tampering (changing data). What if the export filter is changed to include all customers?
Repudiation (denying you did something). For example, no audit event ties export to a user/trace.
Information disclosure (leaking data). Example public link to CSV without time-limited access.
Denial of service (taking the system down). When scripted exports overload the job queue, new jobs wait, latency spikes, and other features slow or stall, causing a small denial-of-service.
Elevation of privilege (getting admin powers you shouldn’t). For example, a missing server-side permission check on “export all.”
The output is a list of candidate risks like those given above.
3. Assess the risks (5 min)
Circle the top 3 risks by impact × likelihood.
Score each risk quickly: Impact (1–3) × Likelihood (1–3).
Pick the three with the highest score.
Write one quick mitigation per risk (rate limit here, encrypt that field, add server-side permission check, add a rollback plan).
For example, in our customer data export scenario, we can pick (i) export by non-owner, (ii) public download link, and (iii) export spam (DoS).
We keep the mitigation plan to one practical control per risk:
Non-owner export: Add server-side authorization check (policy: owner or admin) + unit tests.
Public link: Use time-scoped pre-signed URL + short TTL + one-time token.
Export spam: Add rate limits (per user/IP + global) and a stop switch.
The output can be summarized in a table.
Risk | Control | Test | Owner |
Non-owner export / “export all” without admin | Server-side authorization check (policy middleware or Open Policy Agent); DB Row-Level Security (RLS) for tenant/owner scope | Unit: allow (admin), deny (non-admin). Integration: non-owner gets 403; admin succeeds. DB: RLS blocks cross-tenant read. | Feature team |
Public or long-lived download link (data leak) | Pre-signed URL with short TTL (e.g., 10 min), one-time use, scoped to requesting user | Link expires after TTL; reuse fails; other user cannot download; logs show requester + trace_id | Backend + infra/storage |
Export spam / queue DoS | Per-user & per-IP rate limits + global cap; concurrency limits; feature-flag kill switch ( | Load test returns 429 with | Backend + SRE |
4. Write the one-pager (3 min)
Use the “shift-left” approach and add a short section on Security in the design template of the feature, so the plan is visible from day one.
Shift-left
Data touched: PII fields + where stored/processed
Trust boundaries: Controls at each
Top threats and controls: Your STRIDE top 3
Tests and rollback: Misuse‑case tests; stop switch steps
Make this one-pager mandatory when a feature crosses boundaries, touches PII, or adds a third party. Add <code-owners> so PRs referencing a new design doc auto-tag security reviewers.
Here's an example security one-pager.
John Quest: Create a threat model
Let's try a new example: your team is building a new “Analytics Data Exporter” feature that allows product managers to download large sets of user behavior data as CSV or JSON files.
The data includes anonymized events, timestamps, and aggregated metrics, but it still contains potentially sensitive business insights and user activity patterns.
The exporter works like this:
A signed-in user triggers an export from the analytics dashboard.
The request goes through your API, which validates access and queues an export job.
A background worker generates the file and uploads it to object storage.
The API returns a pre-signed download link for the user.
In the widget below:
Run a STRIDE-lite threat model to identify what could go wrong with this flow.
Then, rank the risks by impact × likelihood, and create a “Top 3 Fixes Table”: one practical control, test, and owner per high-priority risk.
Both impact and likelihood can take values from 1 (minimum) to 3 (maximum).
You’ve just done a real threat model, chosen solid controls, and written them down. Next up, we’ll wire authentication/authorization so those decisions are enforced the same way every time.