threat-modeler
Skill0 starsChanged 6 months agoMITView on GitHub
Build a real threat model for a codebase, service, or feature — before the code review, before the pen test, before launch. Picks the right frame (STRIDE for systems, attack-tree for features, abuser-stories for product flows), works through assets / actors / entry points / trust boundaries via interview + code-read, and produces a structured THREAT_MODEL.md that downstream skills can use to scope a targeted scan. Use when the user says "threat model this", "what's the attack surface", "do a STRIDE analysis", "what could go wrong here", "model the threats", or before any launch touching auth, payments, PII, or multi-tenancy.
- Reads credentials
8 other projects use a version of this.
Adopted by
Most recently taken up by
- jaskirat1616/grok-skillstheir own version, first seen Nov 1, 2026
- alphasafal/production-agent-skillstheir own version, first seen Oct 25, 2026
- JayRHa/agent-skillstheir own version, first seen Oct 15, 2026
- domehahn/skiltheir own version, first seen Jul 28, 2026
- willianbs/skillstheir own version, first seen Jul 18, 2026
- srikanth-manivannan/claude-agent-factorytheir own version, first seen Jun 26, 2026
Other versions8 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 8
- Agile-V/agile_v_skills★ 54same name
- jaskirat1616/grok-skills★ 22same name
- JayRHa/agent-skills★ 12same name
- JayRHa/AgentSkills★ 12same name
- alphasafal/production-agent-skills★ 1same name
- domehahn/skil★ 1same name
- srikanth-manivannan/claude-agent-factory★ 1same name
- willianbs/skills★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository16 other files it gives its agents.
- for-codex/AGENTS.mdAGENTS.md
- api-architectSkill
- browser-qaSkill
- code-auditorSkill
- doc-craftSkill
- git-flow-proSkill
- mcp-forgeSkill
- perf-hunterSkill
- refactor-masterSkill
- resilience-engineerSkill
- schema-architectSkill
- security-sentinelSkill
- ship-itSkill
- test-architectSkill
- type-tightenerSkill
- ui-polishSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
19 rules. 0 are common, 14 are distinctive, and 5 are very specific to this project.
0
Common
Most of the 8 edited versions we read keep these.
14
Distinctive
This author's own choices. Worth a look.
5
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 14
Before any new feature touching auth, payments, file uploads, PII, multi-tenancy, or webhooks
- Distinctive: line 15
Before a SOC 2 / ISO 27001 / pen-test engagement
- Very specific: line 18
Do *not* trigger for: a static code review (use security-sentinel), incident response (you need a responder), or generic "make this secure" …
- Distinctive: line 33
If the model has 80 threats and no ranking, it's a list, not a model.
- Distinctive: line 50
Before asking the user anything, read the code and infer what you can.
- Very specific: line 122
Run the interview short and pointed (see interview-guide.md for the question bank).
- Distinctive: line 130
Entry points: every place untrusted data enters the system.
- Distinctive: line 173
If any assumption flips later (admin app gets a public endpoint.
- Very specific: line 181
Use it as input to security-sentinel — "scan with priority on the top-5 threats from THREAT_MODEL.md"
- Very specific: line 182
Use it as input to api-architect for new endpoints — every new entry point inherits the boundary controls the model demands
- Distinctive: line 194
Don't write a generic threat model from a template.
- Distinctive: line 195
Don't list 80 threats without ranking.
- Distinctive: line 196
Don't conflate threat (what attacker would do) with vulnerability (how the code lets them).
- Distinctive: line 197
Don't model "an APT with unlimited budget" if you're a 5-person company shipping a SaaS.
- Distinctive: line 198
Don't make the model a one-time artifact.
- Very specific: line 205
Bootstrap: read src/api/invitations/ — 5 endpoints, JWT auth on 3, public + token-based on 2.
- Distinctive: line 219
R No audit log on accept → likelihood 3, impact 3 (sev 9): log to existing audit table
- Distinctive: line 221
D No rate limit on /by-token enables 100k req/min crawl → likelihood 4, impact 3 (sev 12): rate-limit by IP and by token-prefix
- Distinctive: line 225
Open questions: do we want a "this invitation has been forwarded" detection?
“Common” is measured: kept by at least 6 in 10 of the 8 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
threat-modeler — figure out what to defend before you defend it
When to use this skill
Trigger when the user wants a planned security view, not a generic scan. Strong signals:
- "threat model this", "do a STRIDE analysis", "what's the attack surface"
- "what could an attacker do here"
- Before any new feature touching auth, payments, file uploads, PII, multi-tenancy, or webhooks
- Before a SOC 2 / ISO 27001 / pen-test engagement
- A new service is being designed and there's no security context yet
Do not trigger for: a static code review (use security-sentinel), incident response (you need a responder), or generic "make this secure" requests where no specific surface has been picked. Pin a scope first.
The output contract
A THREAT_MODEL.md file with two layers:
- A machine-readable section (front matter or JSON block) — downstream skills (
security-sentinel,code-auditor) can parse it to scope what they look for. Lists assets, actors, entry points, trust boundaries, and threats with severity scores. - A human-readable section — the actual narrative. A new engineer should be able to read it in 15 minutes and understand what's worth attacking, what's worth defending, and where the team has deliberately accepted a risk.
Plus three concrete deliverables alongside the doc:
- An assumption log — every claim the model rests on, so the next reviewer can verify or invalidate
- An open-questions list — the things the interview couldn't resolve; goes back to the user or to engineering
- A top-5 risk list — the five things to fix this sprint, ranked by likelihood × impact
If the model has 80 threats and no ranking, it's a list, not a model. Rank or don't ship.
Workflow
1 — Pick the frame
Different surfaces fit different frames. Pick one before starting:
- STRIDE (Spoofing, Tampering, Repudiation, Information disclosure, DoS, Elevation of privilege) — for systems and services. The default for "model this API".
- Attack-tree — for one specific high-value flow (payment, signing, identity proofing). The root is the attacker goal; the branches are how they'd get there.
- Abuser stories — for products with end users (multi-tenant SaaS, marketplaces, social). Mirror image of user stories: "as a malicious tenant I want to see other tenants' data so that…"
- LINDDUN — for privacy-heavy systems (Linkability, Identifiability, Non-repudiation, Detectability, Disclosure, Unawareness, Non-compliance). Pull this in in addition to STRIDE when GDPR/HIPAA/biometric data is on the table.
State the choice in one line in the doc. If a system has two distinct surfaces (e.g., a public API + an admin app), do two passes with two frames.
2 — Bootstrap from code (if there is code)
Before asking the user anything, read the code and infer what you can. Goal: walk into the interview with informed questions, not a blank slate.
This pack is web-app focused — the grep recipes below assume Node.js + React (Express / Fastify / Next.js / NestJS on the server; React / Vue / Svelte on the client). For other stacks adapt the patterns; the categories are universal.
For each entry point, identify:
HTTP routes — what's public, what's authenticated, what's admin-only
# Express / Fastify route surface
rg -t ts -t js '\.(get|post|put|patch|delete)\s*\(' src/ | head -40
# Next.js app router
fd 'route\.(ts|js)' app/ | head -20
# Per-route auth middleware (or lack thereof)
rg -B2 'requireAuth|withAuth|isAuthenticated|@UseGuards' src/Background jobs / cron — what runs on its own authority
rg -t ts -t js 'cron|bullmq|agenda|node-cron|setInterval|setTimeout.*hours?\)'Webhook handlers — what external callers can trigger
rg -t ts -t js 'webhook|/hooks/|stripe.webhook|sendgrid|svix' src/Client-side trust — what the React layer assumes about server response
# dangerouslySetInnerHTML is the canonical XSS surface in React
rg 'dangerouslySetInnerHTML' src/
# direct DOM writes that bypass React
rg 'innerHTML\s*=|document\.write' src/
# routes that take user input directly into the URL
rg 'window\.location|router\.push\([^,)]*(query|params)'File / blob storage — what's user-controlled, what's served back to other users
rg -t ts -t js 'multer|formidable|busboy|S3.*Upload|presigned'Outbound calls — where user input flows out to other services (SSRF surface)
rg -t ts -t js 'fetch\(|axios\.|undici|got\(' src/ | rg 'req\.|body\.|query\.'Database access — what queries take user input
# raw SQL with template strings = parameterization audit
rg -t ts -t js 'raw\(|query\(`|sql`' src/
# Mongo: user-controlled keys can become $-operators
rg -t ts -t js '\.find\(.*req\.body|\.findOne\(.*req\.body' src/Secrets — what's in env vs hardcoded
rg -t ts -t js 'process\.env\.' src/ | head -20
# anything that looks like a baked-in key
rg -t ts -t js -P '(sk_live|sk_test|AIza|AKIA|ghp_)[A-Za-z0-9_-]+'Build a one-page "what I see" summary. This is not the threat model yet. It's the raw map.
3 — Interview the user to fill gaps
The code can't tell you:
- Who's a threat? External attackers, malicious users, malicious tenants in a shared platform, compromised employees, supply-chain attackers, hostile nation-states, customers' angry exes (real for consumer apps), automated scrapers?
- What's actually sensitive? Code doesn't know "this column holds adoption records sealed by court order" vs "this column holds usernames".
- What's the blast radius if X is breached? Regulatory? Reputational? Existential?
- What's been deliberately accepted? "Yes we know the admin app trusts the network — we're inside the VPN and that's by design." Threats that have been considered and accepted are not findings.
Run the interview short and pointed (see interview-guide.md for the question bank). Cap it at 30 minutes — if there's a 90-minute discussion to be had, surface that as "needs follow-up" and don't try to do it inside the threat model.
4 — Map the four pillars
Now write the structured part of the doc:
- Assets: what's worth protecting. Be specific. "User PII" is lazy; "billing addresses, IP at signup time, support-chat transcripts" is real.
- Actors: who would attack and why. Internal vs external. Authenticated vs anonymous. Skilled (nation-state, organized fraud) vs opportunistic (a script kiddie hitting your signup endpoint).
- Entry points: every place untrusted data enters the system. Every. Place. HTTP, GraphQL, webhooks, file upload, OAuth callback, email parsing, push notification tokens, support-form attachments.
- Trust boundaries: where authority shifts. The browser ⇄ backend boundary. Backend ⇄ third-party API. Application ⇄ database. Tenant A ⇄ tenant B. Free user ⇄ paid user ⇄ admin.
Each pillar gets a short numbered list. No paragraphs. The structure exists to be queried.
5 — Walk the frame
For STRIDE: for each asset, for each relevant entry point, ask the six questions:
| Letter | Threat | Example for "user profile API" |
| S | Spoofing | Can someone impersonate another user? (Stolen token, session fixation, password reset weakness) |
| T | Tampering | Can data be modified by someone who shouldn't? (IDOR on PUT, mass-assignment, missing signature on webhook) |
| R | Repudiation | Can a real action be denied? (No audit log on sensitive changes; logs trivially editable) |
| I | Information disclosure | Can data leak to someone who shouldn't see it? (IDOR on GET, verbose errors, side-channels) |
| D | DoS | Can someone make this unavailable? (Unbounded query, no rate limit, expensive endpoints without auth) |
| E | Elevation of privilege | Can a low-priv user become high-priv? (Role check missing on admin route; JWT alg confusion) |
Skip questions that genuinely don't apply ("repudiation isn't relevant to this read-only public endpoint") and say so — silence reads as oversight, but an explicit "N/A: this endpoint is unauthenticated and stateless" reads as rigor.
See stride-reference.md for the full prompt bank per letter, including the modern web concerns STRIDE alone doesn't surface (SSRF, deserialization, subdomain takeover, OAuth scope creep, race conditions on state machines).
6 — Score and rank
For each threat:
- Likelihood: 1 (theoretical) → 5 (someone will try this in the first month)
- Impact: 1 (annoyance) → 5 (existential)
- Severity = likelihood × impact (1–25)
- Mitigation status: existing / partial / none
Sort by severity. Top 5 go into the "fix this sprint" list. The rest sit in the model as known risks with planned mitigations or accepted-risk notes.
Be honest about likelihood. A SQL injection in code that doesn't touch user input is likelihood 1 even if impact is 5. A missing rate limit on /login is likelihood 5 because someone is going to try it tomorrow.
7 — Capture assumptions and open questions
The model is only valid under specific assumptions. Write them down explicitly:
- "Assumes the admin app is only reachable from the corp VPN."
- "Assumes Stripe is the only PCI-handling component."
- "Assumes session tokens in cookies are sufficient for CSRF protection because of SameSite=Lax."
If any assumption flips later (admin app gets a public endpoint; you start handling PANs; you switch to a SPA on a different domain), the model needs a re-run. Note it.
Open questions go in their own section, each with an owner. "Who actually has access to the prod DB read-replica?" is a question for ops, not a guess for the model.
8 — Hand off
Done. The doc is the artifact. Now:
- Use it as input to
security-sentinel— "scan with priority on the top-5 threats from THREAT_MODEL.md" - Use it as input to
api-architectfor new endpoints — every new entry point inherits the boundary controls the model demands - Re-run quarterly or when any assumption changes (whichever is sooner)
Patterns and anti-patterns
✅ Do:
- Threat-model the change, not the whole company. A model for "the new invitations feature" is more useful than a model for "all of our SaaS".
- Name assumptions explicitly. The doc's job is to be invalidated later; named assumptions make that easy.
- Include the things you aren't worried about and why. The absence of a concern reads as oversight; the explicit decision reads as rigor.
- Walk the model with the team after writing it. A model the team disagrees with is more useful than one they merely nod at.
❌ Don't:
- Don't write a generic threat model from a template. If yours could equally describe Slack and Stripe, it's describing nothing.
- Don't list 80 threats without ranking. Pasta isn't a model.
- Don't conflate threat (what attacker would do) with vulnerability (how the code lets them). Threat → goal; vulnerability → mechanism. The model is the goals; the scan finds the mechanisms.
- Don't model "an APT with unlimited budget" if you're a 5-person company shipping a SaaS. Pick threats proportional to who actually targets you.
- Don't make the model a one-time artifact. A model that hasn't been touched in a year is decoration.
Example invocation
User: "We're shipping an invitations feature next week. Threat-model it."
- Frame: STRIDE for the invitation endpoints; abuser stories for the user-facing accept page.
- Bootstrap: read
src/api/invitations/— 5 endpoints, JWT auth on 3, public + token-based on 2. Webhook handler for email-bounce notifications. Send-email goes through a third-party (SendGrid). - Interview (15 min with the user):
- Sensitive assets: pending invitation tokens (one-time signup grant), email addresses (PII), inviter identity.
- Actors of concern: random external attackers, malicious users trying to invite themselves to other orgs, scrapers harvesting valid emails.
- Trust boundaries: browser ⇄ public-accept endpoint; backend ⇄ SendGrid webhook; tenant A ⇄ tenant B.
- Accepted risks: "We don't try to prevent users from inviting fake emails — we expect bounce rates."
- Pillars:
- Assets: invitation token (high), org membership grant (high), email address (medium)
- Actors: ext-anon, ext-authenticated-other-org, malicious-tenant, automated-scraper, sendgrid-compromise
- Entry points: POST /invitations (auth), GET /invitations/by-token/:t (public+rl), POST /accept (public+token), POST /webhooks/sendgrid (public+sig)
- Trust boundaries: 3 listed above
- STRIDE walk — 14 threats identified, e.g.:
- S Token-guessing on /by-token → likelihood 4, impact 4 (sev 16): need 128-bit token + rate limit
- I Enumeration via "email already invited" error → likelihood 5, impact 2 (sev 10): return same response either way
- R No audit log on accept → likelihood 3, impact 3 (sev 9): log to existing audit table
- E Mass-assignment on invitation create lets a regular user set
role: admin→ likelihood 4, impact 5 (sev 20): strict allowlist in the handler - D No rate limit on /by-token enables 100k req/min crawl → likelihood 4, impact 3 (sev 12): rate-limit by IP and by token-prefix
- T SendGrid webhook signature check is currently absent → likelihood 3, impact 4 (sev 12): verify signature with
crypto.timingSafeEqual
- Top-5 ranked for the sprint: mass-assignment, token-guessing, sendgrid signature, rate limit on /by-token, enumeration.
- Assumptions: tokens are 128-bit random from
crypto.randomBytes; SendGrid is the only path; accept endpoint always requires an authenticated session. - Open questions: do we want a "this invitation has been forwarded" detection? (privacy team to decide).
- Output:
docs/security/THREAT_MODEL-invitations.mdwith all of the above, and a structured front-matter block forsecurity-sentinelto consume.
See also
security-sentinel— runs the targeted scan informed by this modelapi-architect— sets the auth/boundary controls the model demands for new endpointscode-auditor— finds the specific bugs corresponding to the threats this model namedresilience-engineer— many tampering/repudiation threats are closed by typed errors + structured logging- Reference files:
stride-reference.md,interview-guide.md
Compatibility
Works in both Claude Code (native SKILL.md auto-routing) and OpenAI Codex CLI (via the for-codex/AGENTS.md routing table). No code execution required — this is an interactive skill that reads files and asks questions; safe to run in any repo.
Attribution
The structural pattern (split planning from finding; bootstrap-from-code then interview; rank by likelihood × impact) is inspired by Anthropic's open-source defending-code-reference-harness, specifically how it separates a planning skill (/threat-model) from a finding skill (/vuln-scan). That repo is Apache 2.0, focused on C/C++ memory bugs.
This skill targets the React + Node.js / TypeScript stack the rest of fullstack-agent-skills is built for. Every workflow step, prompt, grep recipe, STRIDE prompt-bank, interview question, and example is written from first principles for web apps — JWT and OAuth pitfalls, IDOR and mass-assignment, SSRF and CORS, prototype pollution, Next.js getServerSideProps leaks, multi-tenant row-level guards. MIT licensed.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

