Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Conduct threat modeling using STRIDE methodology. Identify threats, assess risks, and design security controls. Use when designing secure systems or assessing application security.
.claude/skills/bagelhole-threat-modeling/SKILL.md| Model | Eval pass | Runs |
|---|---|---|
| gemini-3.6-flash | 100% | 25 |
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 87% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 215% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 115% | 0% |
| case-17 | ✗→✓ | ▲ Improved | 145% | 0% |
| case-20 | ✗→✓ | ▲ Improved | 123% | 0% |
Identify and mitigate security threats during system design.
Use this skill when:
| Threat | Description | Property Violated | Mitigation Examples | |--------|-------------|-------------------|---------------------| | Spoofing | Pretending to be another user or system | Authentication | MFA, mTLS, API key validation, certificate pinning | | Tampering | Modifying data in transit or at rest | Integrity | HMAC, digital signatures, checksums, immutable logs | | Repudiation | Denying having performed an action | Non-repudiation | Audit logging, digital signatures, tamper-evident logs | | Information Disclosure | Exposing data to unauthorized parties | Confidentiality | Encryption (TLS, AES), access controls, data masking | | Denial of Service | Making service unavailable | Availability | Rate limiting, autoscaling, CDN, circuit breakers | | Elevation of Privilege | Gaining unauthorized higher access | Authorization | RBAC, principle of least privilege, input validation |
yaml# stride-worksheet.yaml - Fill out one per component/trust boundary crossing component: name: "API Gateway" owner: "Platform Team" data_classification: "Confidential" trust_boundary: "External -> Internal" threats: - id: T001 category: Spoofing description: "Attacker forges JWT tokens to impersonate users" attack_vector: "Stolen signing key or weak algorithm (HS256 with guessable secret)" likelihood: Medium impact: Critical risk_score: 15 # likelihood(3) x impact(5) existing_controls: - "JWT validation on every request" - "RS256 algorithm with rotated keys" gaps: - "No token binding to device/IP" recommended_mitigations: - "Add token binding claims" - "Implement short-lived tokens (15 min) with refresh" - "Monitor for token reuse from different IPs" status: "Mitigated (partial)" owner: "Auth Team" - id: T002 category: Tampering description: "Man-in-the-middle modifies API requests" attack_vector: "Compromised network between client and gateway" likelihood: Low impact: High risk_score: 8 existing_controls: - "TLS 1.3 enforced" - "HSTS enabled" gaps: [] recommended_mitigations: - "Certificate pinning for mobile clients" status: "Mitigated" owner: "Platform Team" - id: T003 category: Information Disclosure description: "Verbose error messages leak internal details" attack_vector: "Triggering errors returns stack traces, internal IPs, DB schema" likelihood: High impact: Medium risk_score: 12 existing_controls: - "Generic error pages in production" gaps: - "Some microservices return raw exceptions" recommended_mitigations: - "Centralized error handling middleware" - "Error response schema validation" status: "Open" owner: "Backend Team" - id: T004 category: Denial of Service description: "API rate limiting bypass through distributed requests" attack_vector: "Botnet sending requests below per-IP threshold" likelihood: Medium impact: High risk_score: 12 existing_controls: - "Per-IP rate limiting at WAF" gaps: - "No aggregate rate limiting" - "No bot detection" recommended_mitigations: - "Add aggregate rate limiting per endpoint" - "Deploy bot detection (Cloudflare Bot Management)" - "Implement circuit breaker pattern" status: "Open" owner: "Platform Team" - id: T005 category: Elevation of Privilege description: "IDOR allows accessing other users' data" attack_vector: "Manipulating resource IDs in API calls" likelihood: Medium impact: Critical risk_score: 15 existing_controls: - "Authentication required" gaps: - "Authorization checks inconsistent across endpoints" recommended_mitigations: - "Enforce ownership checks on all resource access" - "Use opaque IDs instead of sequential integers" - "Add authorization integration tests" status: "Open" owner: "Backend Team"
Trust Boundary: Internet
==========================
|
[External User]
|
HTTPS/443
|
==========================
Trust Boundary: DMZ
==========================
|
(WAF / CDN)
|
[API Gateway]---->[Auth Service]--->[Identity DB]
|
==========================
Trust Boundary: Internal
==========================
|
[App Service]
/ \
/ \
[Cache] [Message Queue]
|
[Worker Service]
|
==========================
Trust Boundary: Data
==========================
|
[Primary DB]--->[Replica DB]
|
[Object Store]
Legend:
[Box] = Process
(Parens) = External entity / proxy
==== = Trust boundary
---> = Data flowjson{ "summary": { "title": "E-Commerce Platform", "owner": "Security Team", "description": "Threat model for the e-commerce API platform" }, "detail": { "diagrams": [ { "title": "API Data Flow", "diagramType": "STRIDE", "cells": [ { "type": "tm.Actor", "name": "Web Client", "threats": [] }, { "type": "tm.Process", "name": "API Gateway", "threats": ["T001", "T002", "T003", "T004"] }, { "type": "tm.Process", "name": "Order Service", "threats": ["T005"] }, { "type": "tm.Store", "name": "Orders Database", "threats": ["T006"] }, { "type": "tm.Boundary", "name": "DMZ" }, { "type": "tm.Boundary", "name": "Internal Network" } ] } ] } }
yaml# threat-library.yaml - Reusable threat patterns categories: authentication: - id: TL-AUTH-001 name: "Credential stuffing" description: "Attacker uses leaked credential databases to attempt logins" applicable_to: ["login endpoints", "API authentication"] mitigations: ["MFA", "rate limiting", "credential breach monitoring", "CAPTCHA"] - id: TL-AUTH-002 name: "Session hijacking" description: "Attacker steals session tokens via XSS or network sniffing" applicable_to: ["web applications", "APIs with session tokens"] mitigations: ["HttpOnly cookies", "TLS", "session binding", "short TTL"] - id: TL-AUTH-003 name: "OAuth token theft" description: "Access tokens stolen from logs, URLs, or insecure storage" applicable_to: ["OAuth/OIDC integrations"] mitigations: ["PKCE", "short-lived tokens", "token binding", "secure storage"] injection: - id: TL-INJ-001 name: "SQL injection" description: "Malicious SQL in user input executes unauthorized queries" applicable_to: ["database-backed endpoints", "search functionality"] mitigations: ["parameterized queries", "ORM", "input validation", "WAF"] - id: TL-INJ-002 name: "Command injection" description: "User input passed to system commands without sanitization" applicable_to: ["file processing", "system administration features"] mitigations: ["avoid shell commands", "input allowlisting", "sandboxing"] - id: TL-INJ-003 name: "SSRF (Server-Side Request Forgery)" description: "Attacker makes server send requests to internal resources" applicable_to: ["URL fetching features", "webhook handlers", "PDF generators"] mitigations: ["URL allowlisting", "network segmentation", "metadata endpoint blocking"] supply_chain: - id: TL-SC-001 name: "Dependency confusion" description: "Malicious package with internal name published to public registry" applicable_to: ["npm, pip, maven projects using private packages"] mitigations: ["namespace scoping", "registry prioritization", "SBOM monitoring"] - id: TL-SC-002 name: "Compromised CI/CD pipeline" description: "Attacker injects malicious code through build system compromise" applicable_to: ["all software builds"] mitigations: ["SLSA compliance", "signed commits", "ephemeral builders", "provenance"] data: - id: TL-DATA-001 name: "Unencrypted data at rest" description: "Sensitive data stored without encryption on disk or in database" applicable_to: ["databases", "object storage", "backups"] mitigations: ["AES-256 encryption", "KMS-managed keys", "encrypted volumes"] - id: TL-DATA-002 name: "PII exposure in logs" description: "Personal data written to application or infrastructure logs" applicable_to: ["all services handling PII"] mitigations: ["log sanitization", "structured logging", "PII detection scanning"]
| Score | Level | Description | |-------|-------|-------------| | 1 | Very Low | Requires nation-state resources; no known exploits | | 2 | Low | Requires significant expertise and specific conditions | | 3 | Medium | Moderately skilled attacker with available tools | | 4 | High | Script-kiddie level; public exploits available | | 5 | Very High | Trivial to exploit; automated scanning detects it |
| Score | Level | Description | |-------|-------|-------------| | 1 | Negligible | No data exposure; cosmetic only | | 2 | Minor | Limited data exposure; single user affected | | 3 | Moderate | Significant data exposure; service degradation | | 4 | Major | Large-scale data breach; extended outage | | 5 | Critical | Complete system compromise; regulatory breach |
Impact -> 1 2 3 4 5
Likelihood
5 Medium High High Critical Critical
4 Low Medium High High Critical
3 Low Low Medium High High
2 Info Low Low Medium High
1 Info Info Low Low Mediumyamlrisk_treatment: critical: # Score >= 20 action: "Immediate remediation required" sla: "24 hours" approval: "CISO" high: # Score 12-19 action: "Remediation in current sprint" sla: "1 week" approval: "Security Lead" medium: # Score 6-11 action: "Remediation in next sprint" sla: "1 month" approval: "Team Lead" low: # Score 2-5 action: "Track and address in backlog" sla: "1 quarter" approval: "Team Lead" info: # Score 1 action: "Accept risk and document" sla: "None" approval: "Team Lead"
bash# Run Threat Dragon locally with Docker docker run -d \ --name threat-dragon \ -p 3000:3000 \ -e ENCRYPTION_KEYS='["threat-dragon-encryption-key-change-me"]' \ -e NODE_ENV=production \ owasp/threat-dragon:v2.2.0 # Access at http://localhost:3000 # Or install as desktop application # Download from: https://github.com/OWASP/threat-dragon/releases
yaml# .github/workflows/threat-model-review.yml name: Threat Model Review on: pull_request: paths: - 'docs/threat-model/**' - 'architecture/**' jobs: validate: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Validate threat model files run: | for model in docs/threat-model/*.yaml; do echo "Validating $model..." python -c " import yaml, sys with open('$model') as f: data = yaml.safe_load(f) required = ['component', 'threats'] for r in required: if r not in data: print(f'ERROR: Missing required field: {r}') sys.exit(1) for t in data.get('threats', []): if t.get('status') == 'Open' and t.get('risk_score', 0) >= 12: print(f'WARNING: High-risk open threat: {t[\"id\"]} - {t[\"description\"]}') print(f'OK: {len(data[\"threats\"])} threats documented') " done - name: Check for unaddressed critical threats run: | CRITICAL=$(grep -r "risk_score: \(1[5-9]\|2[0-5]\)" docs/threat-model/*.yaml | grep "status: \"Open\"" | wc -l) if [ "$CRITICAL" -gt 0 ]; then echo "WARNING: $CRITICAL critical/high-risk threats still open" echo "Review required before merging architectural changes" fi
| Problem | Cause | Solution | |---------|-------|----------| | Threat model sessions are unproductive | Participants don't understand the system | Share architecture docs before the session; include a system walkthrough | | Too many threats identified | Scope too broad | Focus on one component or trust boundary per session | | Threats are too vague | No structured methodology | Use STRIDE per element; fill in the worksheet template for each | | Team doesn't follow up on findings | No ownership or tracking | Assign each threat to a team with SLA; track in issue tracker | | Threat model becomes stale | No trigger to update | Require review on architecture changes (CI/CD gate on diagram changes) | | Disagreements on risk scores | Subjective scoring | Use the scoring matrix consistently; calibrate with historical incidents |
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 29,879 | 29,752 | -0% | 1 | 1 | 0% | 4,426 | 8,260 | +87% | 0 | 0 | — |
case-02 | fail→pass | 13,537 | 20,844 | +54% | 1 | 1 | 0% | 2,512 | 7,918 | +215% | 0 | 0 | — |
case-03 | fail→pass | 24,781 | 23,047 | -7% | 1 | 1 | 0% | 3,388 | 7,286 | +115% | 0 | 0 | — |
case-04 | pass→pass | 29,118 | 14,315 | -51% | 1 | 1 | 0% | 4,521 | 6,263 | +39% | 0 | 0 | — |
case-05 | fail→fail | 12,043 | 13,683 | +14% | 1 | 1 | 0% | 498 | 4,514 | +806% | 0 | 0 | — |
case-06 | pass→pass | 24,650 | 30,926 | +25% | 1 | 1 | 0% | 3,461 | 7,957 | +130% | 0 | 0 | — |
case-07 | pass→pass | 15,690 | 10,484 | -33% | 1 | 1 | 0% | 1,808 | 5,539 | +206% | 0 | 0 | — |
case-08 | pass→pass | 17,600 | 23,549 | +34% | 1 | 1 | 0% | 1,972 | 5,999 | +204% | 0 | 0 | — |
case-09 | pass→pass | 11,685 | 11,966 | +2% | 1 | 1 | 0% | 968 | 4,981 | +415% | 0 | 0 | — |
case-10 | pass→pass | 12,538 | 5,925 | -53% | 1 | 1 | 0% | 1,225 | 4,652 | +280% | 0 | 0 | — |
case-11 | pass→pass | 11,224 | 12,352 | +10% | 1 | 1 | 0% | 932 | 4,987 | +435% | 0 | 0 | — |
case-12 | pass→pass | 14,620 | 8,987 | -39% | 1 | 1 | 0% | 1,478 | 4,523 | +206% | 0 | 0 | — |
case-13 | pass→pass | 12,697 | 16,510 | +30% | 1 | 1 | 0% | 2,589 | 6,045 | +133% | 0 | 0 | — |
case-14 | pass→pass | 19,861 | 16,893 | -15% | 1 | 1 | 0% | 2,199 | 5,912 | +169% | 0 | 0 | — |
case-15 | pass→pass | 18,364 | 16,406 | -11% | 1 | 1 | 0% | 2,673 | 5,736 | +115% | 0 | 0 | — |
case-16 | pass→pass | 19,275 | 20,040 | +4% | 1 | 1 | 0% | 2,199 | 6,401 | +191% | 0 | 0 | — |
case-17 | fail→pass | 17,331 | 13,277 | -23% | 1 | 1 | 0% | 2,138 | 5,244 | +145% | 0 | 0 | — |
case-18 | pass→fail | 24,038 | 21,003 | -13% | 1 | 1 | 0% | 3,034 | 7,289 | +140% | 0 | 0 | — |
case-19 | pass→pass | 24,015 | 28,654 | +19% | 1 | 1 | 0% | 2,613 | 7,519 | +188% | 0 | 0 | — |
case-20 | fail→pass | 19,031 | 9,652 | -49% | 1 | 1 | 0% | 2,114 | 4,716 | +123% | 0 | 0 | — |
case-21 | fail→fail | 17,209 | 22,725 | +32% | 1 | 1 | 0% | 2,436 | 6,415 | +163% | 0 | 0 | — |
case-22 | fail→pass | 22,803 | 20,740 | -9% | 1 | 1 | 0% | 2,416 | 6,319 | +162% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +23 percentage points is the difference between those two pass rates over the 22 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.