threat-model
Produce a STRIDE threat model from a design doc, architecture description, or feature spec — assets and trust boundaries first, threats anchored to boundary crossings with concrete attack scenarios, severity-ranked with verifiable mitigations. Use when the user asks to threat-model a design, run a security review of an architecture, ask "how could this be attacked", or needs security sign-off input before build.
Other ways to install
With the sibling skills it hands off to:
The whole pack it belongs to:
By hand, from a clone of the repo:
In Claude Code, with the solution-architect plugin installed, invoke it as:
Try it
A realistic prompt from the skill's acceptance evals:
Threat model this design: a multi-tenant reporting service where customers upload CSVs, we process them in a worker, and results are served from an S3 bucket via signed URLs.
What a good result looks like
Example output
document-upload feature → 6 ranked findings · the skill's own worked example, source
New feature: customers upload contract PDFs for e-signing. Browser gets a presigned S3 URL from
upload-api(authenticated), uploads directly to thecontractsbucket, thenupload-apienqueues a message;doc-processorconsumes it, runs OCR via a third-party API, and writes extracted text to Postgres. Support staff can view any customer's documents in the admin panel to help with signing issues. Multi-tenant SaaS, tenant ID in the JWT.
System summary
Assets (ranked): customer contracts (legal PII — top asset), extracted contract text in Postgres, S3 credentials / presigned-URL minting capability, OCR API key. Entry points: upload-api (authn'd HTTP), direct browser→S3 upload, SQS queue into doc-processor, third-party OCR API responses, admin panel. Trust boundaries: internet→upload-api, internet→S3 (presigned), upload-api→queue→doc-processor, doc-processor→OCR vendor (data leaves our trust domain), doc-processor→Postgres, support-staff→admin panel, tenant→tenant throughout. [assumption] Presigned URLs are PUT-only. [assumption] OCR vendor is contractually approved for PII.
Findings
🟥 TM-1 — Cross-tenant document read via unscoped presigned URLs (boundary: internet→S3; STRIDE: I, E) Scenario: a tenant inspects their presigned URL, finds object keys are contracts/{uuid}.pdf with no tenant prefix; any later GET-capable URL or a key-guessing bug exposes other tenants' contracts — compromise of the top asset. Existing mitigation: none stated in the design. Recommended: keys become contracts/{tenant_id}/{uuid}.pdf, minted only from the JWT's tenant claim, GET URLs scoped to prefix and ≤5 min. Verify: CI test fetches tenant B's key with tenant A's session — must 403.
🟥 TM-2 — Malicious file detonates in doc-processor (boundary: queue→doc-processor; STRIDE: T, E) Scenario: attacker uploads a crafted PDF (parser exploit, zip bomb, SSRF-triggering embedded URL); doc-processor parses it with vendor-library defaults and processor credentials. RCE here reaches Postgres and the OCR key. Existing mitigation: none stated. Recommended: validate content-type + size at presign and on consume; parse inside a sandboxed, least-privilege worker (no Postgres write role until post-parse); pin and patch the parser. Verify: corpus of hostile PDFs in CI lands in DLQ, not crash-loop or exec.
🟧 TM-3 — Support staff can browse any tenant's contracts with no audit trail (boundary: human→system; STRIDE: I, R; insider pass) Scenario: a support login (insider or phished) bulk-reads contracts across tenants; the design grants "view any customer's documents" with no purpose-binding or logging — undetectable until external disclosure. Existing mitigation: admin panel is authenticated. Recommended: case-bound access (support sees a document only via an open ticket reference), immutable audit log of every view, MFA on support accounts. Verify: admin-action integration test asserts the audit row; access without ticket reference → denied.
🟧 TM-4 — Queue accepts unauthenticated/poisoned messages (boundary: upload-api→queue; STRIDE: S, T) Scenario: any internal workload (or attacker post-TM-2) enqueues {tenant_id: victim, s3_key: attacker_file}; doc-processor trusts the message and writes attacker text into the victim tenant's Postgres rows. Existing mitigation: queue is network-internal [assumption: flat internal trust]. Recommended: doc-processor re-derives tenant from the S3 key prefix (post-TM-1) instead of trusting the message field; schema-validate on consume; producer allow-list via IAM. Verify: message with mismatched tenant/key → rejected with alert.
🟨 TM-5 — Contract PII leaves trust domain to OCR vendor unminimized (boundary: doc-processor→vendor; STRIDE: I) Scenario: full contracts ship to the vendor; a vendor breach exposes the top asset with no detection on our side. Requires the vendor's failure, hence 🟨 not 🟧. Existing mitigation: [assumption] contractual DPA. Recommended: confirm the DPA covers this data class; disable vendor-side retention; log per-document egress so exposure is enumerable after a vendor incident. Verify: vendor account settings reviewed + egress log row asserted in tests.
🟨 TM-6 — Unbounded uploads as cost/availability attack (boundary: internet→S3; STRIDE: D) Scenario: a scripted tenant requests thousands of presigned URLs and uploads max-size files; S3 cost spike and OCR-queue saturation delay every tenant's processing (noisy-neighbor DoS). Existing mitigation: authn required. Recommended: per-tenant presign rate limit + size cap at presign time; queue depth alarm with per-tenant fairness. Verify: load test on the presign endpoint shows throttling before queue saturation.
n/a ledger
Repudiation at internet→S3: n/a beyond TM-3's audit log — S3 access logging assumed on. DoS at admin panel: internal user base, marginal.
Authz / insider pass
Authz: TM-1, TM-4 (tenant→tenant). Insider: TM-3. Sweeps produced findings — no all-clear claimed.
Questions for the team
- Are presigned URLs PUT-only, and is there any GET path today? (confirms or escalates TM-1)
- Does the OCR vendor contract cover contract PII, and is vendor-side retention off? (resolves TM-5's assumptions)
Out of scope
E-signing flow itself (separate design); S3 bucket-policy review (assumed account-standard); browser-side threats (XSS) — covered by the web app's existing model.
Revisit trigger
New entry point (e.g. email-in ingestion), new document consumer, or any change to support-access rules.
How it's checked
Measured against plain Claude Code (2026-10-23): it met 86% of its checks, against 57% without it, and a blind judge preferred it. How skills are checked
21 assertions across 3 acceptance evals, and 8 trigger queries. Every skill's checks
What the output must do
When it should and shouldn't activate
Should activate:
- Threat model this design
- Run STRIDE on this architecture before we build it
- What could an attacker do to this system as designed?
- Security review of this design doc, with trust boundaries and attack scenarios
Should leave to another skill:
- Review this diff for exploitable security bugs
- Threat model my AI agent's tool and data access
- Audit this UI for accessibility barriers
- Convene a council to deliberate this architecture
Related skills
design-doc, devils-advocate, postmortem-generator, reverse-architecture, sonar-review
Source
SKILL.md · the whole folder on GitHub.