Claude Skill

sota-threat-modeling

State-of-the-art threat modeling for both designing new systems and auditing existing ones. Use when designing a feature, service, integration, or architecture that touches untrusted input, new trust boundaries, sensitive data, or third-party dependencies (BUILD mode), and when r

LLM Mart · 0 points · 7 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download martinholovsky-sota-skills-skills_sota-threat-modeling-582d6f9.zip · 42 KB
Part of martinholovsky/sota-skills — 39 skills

Install

skills CLI npx skills add https://github.com/martinholovsky/SOTA-skills/tree/main/skills/sota-threat-modeling
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install martinholovsky-sota-skills@llmmart
Git git clone https://github.com/martinholovsky/SOTA-skills.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole martinholovsky/sota-skills collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

SOTA Threat Modeling

Purpose

Threat modeling answers Shostack's four questions with engineering rigor:

  1. What are we working on? (decompose: DFD, trust boundaries, assets, actors)
  2. What can go wrong? (enumerate: STRIDE/LINDDUN per element, catalogs, attack trees)
  3. What are we going to do about it? (treat: mitigate/accept/transfer/avoid, map to requirements and tests)
  4. Did we do a good job? (verify: abuse-case tests, residual risk review, re-model triggers)

This skill operationalizes those questions in two modes. Never produce a threat model that is only prose — every threat must land as a tracked requirement, a test, or an explicitly accepted risk with an owner.

BUILD Mode — Threat-Model-While-Designing

Run this workflow whenever designing anything that crosses a trust boundary. Scale effort to risk: a 15-minute "four questions" pass for a small feature; a full STRIDE-per-interaction model for a new service or auth flow.

Workflow

  1. Scope the delta. Model what is new or changed, not the whole system. List new entry points, new data classes, new dependencies, new actors.
  2. Draw the DFD as text/mermaid (see rules/02). Mark trust boundaries explicitly. If you cannot draw a boundary, you do not understand the design yet — stop and ask.
  3. Pick the methodology (see rules/01): STRIDE-per-interaction by default; add LINDDUN if personal data flows; attack trees for a single high-value asset; four-questions-only for low-risk deltas.
  4. Enumerate threats crossing each boundary using the per-component catalogs in rules/03. Write each threat as: actor → action → asset → impact. No vague entries ("hacking", "data breach").
  5. Rate and treat each threat (see rules/04): likelihood × impact matrix, then accept / mitigate / transfer / avoid. Every mitigation becomes a security requirement with an ID.
  6. Emit artifacts (see rules/05): threat model doc, security requirements backlog entries, abuse cases as test stubs, and re-modeling triggers.
  7. Wire into delivery. Reference requirement IDs in the design doc, tickets, and PR descriptions. A threat without a tracked artifact does not exist.

Continuous / incremental (agile, PR reviews)

  • Threat model the story, not the sprint. Add a "Security notes" section to design docs and PR descriptions for any change matching a re-model trigger: new dependency, new endpoint/route/queue/cron/webhook, new trust boundary, new data class, auth/authz change, file/deserialization handling.
  • In PR review, run a micro-STRIDE on the diff only: what new input enters? whose privilege executes it? what does it write or call? Takes 5 minutes; catches the majority of design-level regressions.

AUDIT Mode — Reconstructing a Threat Model from Code

Use when handed an existing system with no (trustworthy) threat model. Goal: rebuild the implicit model from artifacts, then diff intended vs. actual controls. Full procedure in rules/06.

Workflow

  1. Inventory entry points from code (see rules/02 §extraction): routes, queue consumers, cron jobs, webhooks, third-party callbacks, CLI/admin tools, file uploads, IaC-exposed ports.
  2. Reconstruct the DFD from the inventory: processes, stores, external entities, flows; infer trust boundaries from network topology, authn checkpoints, and IAM policies.
  3. Identify assets and actors from schemas, secrets handling, and config.
  4. Run the catalogs (rules/03) against each component; for every catalog item record: control present / absent / partial, with file:line evidence.
  5. Gap analysis: rank absent/partial controls by exploitability × blast radius; distinguish "missing control" from "missing defense-in-depth".
  6. Report findings in the standard format below.

Severity conventions

Severity Definition
Critical Remotely exploitable now, by an unauthenticated or low-priv actor, leading to full compromise of a key asset (RCE, auth bypass, mass data exfil). Fix before anything else ships.
High Exploitable with realistic preconditions (one valid account, one misconfig, MitM position) compromising a key asset; or a Critical with a single weak mitigating layer. Fix this sprint.
Medium Requires chaining, elevated access, or unusual conditions; or impacts a secondary asset; or defense-in-depth gap on a Critical path. Schedule.
Low Hardening, hygiene, info disclosure of low-value data, theoretical with strong existing controls. Backlog.

Severity = exploitability × impact in this deployment context — never copy a CVE/CVSS base score without environmental adjustment (see rules/04).

Finding format (every finding, no exceptions)

[SEV] TITLE (component, STRIDE/LINDDUN class)
Location: path/to/file.py:123 (and IaC/config refs)
Threat: <actor> can <action> via <vector> because <missing/weak control>,
        impacting <asset> (<C/I/A/privacy impact>).
Evidence: code excerpt or config line proving the gap.
Recommendation: specific control + where it goes; map to requirement ID.
Residual risk if accepted: one sentence.

Rules Index

File Read this when...
rules/01-methodologies.md Choosing between STRIDE, LINDDUN, PASTA, attack trees, kill chains; deciding lightweight vs. heavyweight; setting up continuous/PR-level threat modeling.
rules/02-decomposition.md Drawing DFDs in mermaid, defining trust boundaries, listing entry points/assets/actors/privilege levels; extracting all of these from an existing codebase.
rules/03-threat-catalogs.md Enumerating threats for a specific component: web frontend, API, database, message queue, file storage, CI/CD, mobile, LLM agent/tool-use, cloud/IAM.
rules/04-risk-rating-treatment.md Rating threats (DREAD pitfalls, CVSS usage, L×I matrices), choosing accept/mitigate/transfer/avoid, mapping mitigations to requirements and tests, documenting residual risk.
rules/05-outputs-operationalization.md Writing the threat model document, building the security requirements backlog, turning abuse cases into tests, keeping the model alive (re-model triggers).
rules/06-audit-reconstruction.md Auditing an existing system: reconstructing the model from code, control-presence matrix, gap analysis, severity calibration, reporting.

Load only the files you need; rules/02 + rules/03 cover 80% of day-to-day work.

Top-10 Non-Negotiables

  1. No model without a diagram. Every threat model includes a DFD (mermaid or ASCII) with explicit trust boundaries. Prose-only models hide boundary confusion.
  2. Threats are sentences, not nouns. Actor → action → asset → impact. "SQL injection" is a vector; "anonymous user exfiltrates the orders table via unparameterized search query" is a threat.
  3. Every entry point gets enumerated — including queues, cron, webhooks, callbacks, admin tooling, and CI/CD. HTTP routes are never the whole attack surface.
  4. Trust boundary crossings drive enumeration. Apply STRIDE per interaction at each crossing; data inside one boundary at one privilege level rarely needs the full treatment.
  5. Personal data ⇒ LINDDUN pass. STRIDE does not cover linkability, identifiability, or non-compliance; run a privacy pass whenever PII flows or is stored.
  6. Rate with likelihood × impact in context. Never ship raw DREAD scores or unadjusted CVSS base scores as priorities.
  7. Every threat gets a disposition. Mitigate (→ requirement ID + test), accept (→ named owner + expiry date), transfer, or avoid. "Noted" is not a disposition.
  8. Mitigations become tests. Each mitigated threat yields at least one abuse-case test (unit, integration, or rule-based check) that fails if the control regresses.
  9. LLM/agent components are first-class attack surface. Model prompt injection, tool-call abuse, excessive agency, and data exfil via outputs for any system invoking an LLM with tools or retrieved content.
  10. Models expire. Define re-model triggers (new dependency, new trust boundary, new data class, auth change) in the document itself; an undated, trigger-less threat model is treated as absent in audits.
Files (sota-skills)
  • rules
    • 01-methodologies.md 13.8 KB
      # 01 — Methodology Selection & Continuous Threat Modeling
      
      Pick the cheapest methodology that surfaces the threats that matter for THIS
      change. Methodology is a lens, not a deliverable; the deliverable is a set of
      dispositioned threats (see `04`, `05`).
      
      ## 1. Decision table — which method, when
      
      | Situation | Method | Why |
      |---|---|---|
      | Default for any service/feature with a DFD | STRIDE-per-interaction | Best coverage-to-effort for technical threats at boundaries |
      | Quick element-level sweep, early sketch | STRIDE-per-element | Faster, coarser; fine when interactions aren't designed yet |
      | Personal data collected/stored/shared | LINDDUN (added to STRIDE, never instead) | STRIDE misses linkability, identifiability, non-compliance |
      | One crown-jewel asset (signing key, payment flow, model weights) | Attack tree | Forces enumeration of ALL paths to one goal, incl. non-technical |
      | Business-risk-driven, exec-facing, regulated org | PASTA (or PASTA-lite) | Ties threats to business impact; expensive — don't use for sprints |
      | Understanding a realistic adversary's end-to-end campaign | Kill chain / ATT&CK mapping | Validates detection & response coverage, not just prevention |
      | Small, low-risk delta; PR review; time-boxed | Shostack's four questions only | 15 minutes of structured thinking beats zero minutes of process |
      | Agentic / multi-agent AI system | STRIDE-per-interaction + agent catalog (`03` §8); CSA MAESTRO's layered analysis for complex multi-agent ecosystems | Agent threats (goal hijack, memory poisoning, collusion) span layers STRIDE alone doesn't name |
      
      Rationale: methods fail in predictable ways — STRIDE over-generates duplicates,
      LINDDUN is privacy-only, PASTA stalls in stage ceremony, attack trees go stale.
      Combine narrowly; never run all of them "to be thorough."
      
      ## 2. STRIDE — per-element vs. per-interaction
      
      ### The mnemonic, with the property each violates
      
      | Threat | Violated property | Canonical question |
      |---|---|---|
      | **S**poofing | Authentication | Can the caller lie about who it is? |
      | **T**ampering | Integrity | Can data/code be modified in flight or at rest? |
      | **R**epudiation | Non-repudiation | Can an actor deny an action because we can't prove it? |
      | **I**nformation disclosure | Confidentiality | Can data leak to someone unauthorized? |
      | **D**enial of service | Availability | Can the element be exhausted, crashed, or locked? |
      | **E**levation of privilege | Authorization | Can a low-priv actor do high-priv things? |
      
      ### Per-element (coarse)
      
      Apply the applicable subset to each DFD element type:
      
      | Element | S | T | R | I | D | E |
      |---|---|---|---|---|---|---|
      | External entity | x | | x | | | |
      | Process | x | x | x | x | x | x |
      | Data store | | x | x | x | x | |
      | Data flow | | x | | x | x | |
      
      Use when: the design is a sketch, you need breadth in 30 minutes. Cost: misses
      threats that only exist because of WHO talks to WHOM (e.g., a queue consumer
      trusting producer-supplied IDs).
      
      ### Per-interaction (default)
      
      For each data flow that **crosses a trust boundary**, ask all six STRIDE
      questions about the tuple *(source, flow, destination)*. Skip flows that stay
      inside one boundary at one privilege level unless they carry a crown-jewel
      asset. Rationale: ~90% of exploitable design flaws live at boundary crossings;
      per-interaction concentrates effort there and naturally produces
      *actor → action → asset* threat sentences.
      
      ### Worked mini-example
      
      ```mermaid
      flowchart LR
        U[Browser] -->|1 POST /orders JWT| A[API]
        A -->|2 SQL| D[(orders DB)]
        A -->|3 publish order.created| Q[[queue]]
        Q -->|4 consume| W[Fulfillment worker]
        subgraph TB1[Internet → DMZ boundary]
          U
        end
        subgraph TB2[Backend boundary]
          A; D; Q; W
        end
      ```
      
      STRIDE-per-interaction on flow 1 (crosses TB1→TB2):
      - **S**: forged/alg-confused JWT → API acts as another user. Mitigation: verify
        alg allowlist + issuer + audience; requirement `SR-101`.
      - **T**: order body altered client-side (price field trusted). Mitigation:
        server-side price lookup; `SR-102`.
      - **R**: user disputes placing order. Mitigation: signed audit log incl. JWT sub
        + request hash; `SR-103`.
      - **I**: order IDs sequential → enumeration of others' orders via GET.
        Mitigation: authz check object-level + UUIDv7; `SR-104`.
      - **D**: unbounded order payload / no rate limit. Mitigation: body size cap +
        per-user rate limit; `SR-105`.
      - **E**: `role` claim taken from request body, not token. Mitigation: derive
        authz only from verified token/server state; `SR-106`.
      
      Flow 4 (inside TB2) still gets a pass because the worker acts at higher
      privilege than the producer's data deserves: poisoned `order.created` message
      with attacker-chosen `shipping_address` and `sku` → **T/E** on the worker.
      Lesson: a queue is a deferred entry point; producer authentication and message
      schema validation are boundary controls (see `03` §queue).
      
      ## 3. LINDDUN — privacy threats (run WITH STRIDE when PII flows)
      
      | Threat | Question to ask per flow/store holding personal data |
      |---|---|
      | **L**inking | Can two records/actions be tied to the same person across contexts? |
      | **I**dentifying | Can a "pseudonymous" subject be re-identified (quasi-identifiers, logs, analytics)? |
      | **N**on-repudiation | Can the subject NOT plausibly deny an action they should be able to deny? (inverse of STRIDE-R) |
      | **D**etecting | Can an outsider learn a person exists in the system (login timing, "email already registered")? |
      | **D**ata disclosure | Is more personal data collected/stored/shared than the purpose needs? |
      | **U**nawareness & unintervenability | Does the subject not know what's collected/shared — or have no way to access, correct, or erase it? |
      | **N**on-compliance | Does the flow violate stated policy / GDPR-class obligations (retention, purpose, residency)? |
      
      Use LINDDUN GO (card-style, per-flow prompts) for sprint-speed work; full
      LINDDUN per-element only for new products handling sensitive categories.
      Mini-example: the orders DFD above stores `shipping_address`. LINDDUN adds:
      **L** — address joins orders across guest checkouts into a profile; **D**etect —
      "email already used" on checkout leaks account existence; **N**on-compliance —
      no retention period on fulfilled orders. None of these fall out of STRIDE.
      
      ## 4. PASTA — when business context must drive the model
      
      Seven stages: (1) business objectives → (2) technical scope → (3) decomposition
      → (4) threat analysis (intel-driven) → (5) vulnerability analysis → (6) attack
      modeling/simulation → (7) risk & impact analysis. Use full PASTA only when the
      audience is risk owners/executives and the system is business-critical or
      regulated. Otherwise run **PASTA-lite**: write stages 1–2 as a half-page
      "business impact preamble" on top of a STRIDE model — it sharpens severity
      ratings (`04`) by naming what the business actually loses. Pitfall: PASTA used
      as ceremony produces 40-page documents nobody re-reads; cap the artifact.
      
      ## 5. Attack trees
      
      Root = attacker goal (a state, not an action): "Read another tenant's
      documents." Children = OR/AND-decomposed subgoals down to concrete attack
      steps. Annotate leaves with cost/skill/detectability; prune branches whose
      cheapest path is dominated by another branch.
      
      ```
      GOAL: read another tenant's documents
      ├─ OR exploit the app
      │  ├─ IDOR on GET /docs/{id} (no tenant check)        [cheap → mitigate first]
      │  └─ SQLi in search → cross-tenant SELECT
      ├─ OR exploit the platform
      │  ├─ AND: SSRF → cloud metadata creds → S3 GetObject on shared bucket
      │  └─ misconfigured bucket policy (public-read)
      └─ OR exploit people/process
         └─ phish support agent → admin "impersonate" feature
      ```
      
      Use when: one asset dominates the risk profile, or to communicate "why this
      mitigation" to non-modelers. AND-nodes show where a single control kills a
      whole branch — invest there. Keep trees ≤3 levels; deeper trees rot.
      
      ## 6. Kill chains / ATT&CK
      
      Map a realistic campaign across recon → initial access → execution →
      persistence → privilege escalation → lateral movement → exfiltration. Use to
      answer "would we DETECT and STOP this, and at which stage?" — i.e., to threat
      model detection/response, logging coverage, and segmentation, which
      STRIDE-per-interaction does not test. For each kill-chain stage, name the
      telemetry that would fire; a stage with no telemetry is a logging requirement
      (feeds `05` backlog). Don't use kill chains to find design flaws — that's
      STRIDE's job.
      
      ## 7. Lightweight: the four questions beat heavyweight process when...
      
      - The delta is small and inside existing boundaries (new field, new report).
      - The team will genuinely do a 15-minute pass but would skip a 2-hour workshop.
      - You are in a PR review (see §8).
      
      A four-questions pass still produces artifacts: 3–10 threat sentences, each
      with a disposition. If the pass surfaces a new trust boundary, new data class,
      or new dependency, **escalate** to a full STRIDE model — that's the upgrade
      trigger, codify it in the team's definition of ready.
      
      ### Worked four-questions pass (feature: "export my data as CSV")
      
      1. *What are we working on?* New `GET /export` endpoint → async job → CSV in
         the uploads bucket → emailed signed link. New flow crosses: user→API,
         job→bucket, email→user.
      2. *What can go wrong?*
         - T1: user A triggers export, job exports ALL users' rows (missing tenant
           scope in the bulk query — bulk paths often bypass per-row authz).
         - T2: signed link forwarded/leaked from email → anyone reads the CSV
           (email is an untrusted store; long-expiry link = standing credential).
         - T3: CSV formula injection — `=HYPERLINK(...)` in user-controlled fields
           executes in victims' spreadsheets (your file, their machine).
         - T4: unbounded concurrent exports exhaust DB/worker (D).
      3. *What are we going to do?* T1 → reuse tenant-scoped repo + abuse test
         (mitigate); T2 → 15-min expiry + require login to download (mitigate);
         T3 → prefix `'` on `=+-@` cells (mitigate); T4 → 1 concurrent export/user
         (mitigate). No accepts needed.
      4. *Did we do a good job?* Four threats, four requirements, three tests;
         re-check at next data-class change. Elapsed: ~15 minutes. T3 is the kind
         of threat a checklist-free brainstorm misses — which is why even the
         lightweight pass consults the relevant catalog (`03` §5 file pipelines).
      
      ### Enumeration aids (any methodology)
      
      - **Elevation-of-Privilege / cornucopia card decks:** use for team workshops
        to break "blank page" paralysis; cards are prompts, the output is still
        threat sentences in the table.
      - **Organizational threat library:** harvest recurring threats + standard
        mitigations from past models into a reusable library keyed by component
        type; new models import and check applicability rather than re-deriving.
        This is the highest-leverage maturity step after triggers (`05` §4).
      - **LLM-assisted enumeration:** useful as a breadth generator against your
        DFD; treat output as candidate threats requiring human reachability
        triage — never paste raw generation into the model (violates the triage-
        capacity rule below).
      
      ## 8. Continuous / incremental threat modeling (agile + PRs)
      
      Rules:
      
      1. **Baseline once, then delta forever.** Maintain one living baseline model
         per service (`05` §living). Sprint work models only the diff against it.
      2. **Re-model triggers gate stories.** A story matching any trigger — new
         dependency, new entry point (route/queue/cron/webhook/callback), new trust
         boundary, new data class, authn/authz change, crypto change, file or
         deserialization handling — requires a threat-model note before merge.
      3. **PR micro-STRIDE (5 minutes, on the diff only):**
         - What NEW input enters, and from whom? (S, T)
         - At whose privilege does the new code run, and what can it now reach? (E)
         - What does it write, emit, or call — including logs and third parties? (I, R)
         - What happens at 1000× volume or with a 100 MB payload? (D)
         Record the answers in the PR description under `## Security notes`; "no new
         input, no privilege change, no new sink" is a valid and useful answer.
      4. **Timebox enumeration, not treatment.** Cut off brainstorming at the
         timebox; never cut off writing dispositions for what you found.
      5. **One owner per model.** The service's tech lead owns baseline freshness;
         audits (`06`) treat a stale baseline (no update across a trigger-matching
         change) as a finding.
      
      Anti-patterns: threat modeling only at "security review" milestones (too late,
      batch too big); tool-generated 200-threat reports pasted into tickets (nobody
      triages them — generate ≤ the team's triage capacity); modeling the whole
      system every sprint (re-derives known results, exhausts goodwill).
      
      ## Audit checklist
      
      - [ ] A documented methodology choice exists and matches the system's risk
            profile (not "we ran a tool").
      - [ ] STRIDE applied per-interaction at every trust boundary crossing; flows
            skipped only when source and destination share boundary AND privilege.
      - [ ] LINDDUN (or equivalent privacy pass) performed wherever personal data is
            collected, stored, or shared; linkability, detectability, and
            intervenability (subject can access/correct/erase) considered.
      - [ ] Crown-jewel assets have an attack tree or equivalent all-paths analysis.
      - [ ] Detection/response coverage assessed (kill-chain or ATT&CK mapping) for
            at least the top abuse scenario; logging gaps captured as requirements.
      - [ ] Every threat is an actor→action→asset→impact sentence, not a category.
      - [ ] Re-model triggers are defined and observably enforced (PRs matching
            triggers contain security notes; baseline model updated after them).
      - [ ] Enumeration volume matches triage capacity — no untriaged threat dumps.
      - [ ] Lightweight passes escalate to full models when triggers fire (evidence:
            at least one escalation in history, or no trigger-matching changes).
      
    • 02-decomposition.md 12.3 KB
      # 02 — System Decomposition: DFDs, Trust Boundaries, and Extraction from Code
      
      Decomposition quality caps threat-model quality: you cannot enumerate threats
      against elements you never drew. This file covers (A) building the model and
      (B) extracting it from an existing codebase.
      
      ## A. Building the model
      
      ### 1. DFD element vocabulary
      
      Use exactly four element types plus boundaries — more notation adds cost, not
      threats:
      
      | Element | Mermaid convention | Examples |
      |---|---|---|
      | External entity | `E[Name]` rectangle | user browser, third-party API, attacker, payment provider |
      | Process | `P(Name)` rounded | API service, worker, lambda, cron job, LLM agent |
      | Data store | `D[(Name)]` cylinder | Postgres, S3 bucket, Redis, browser localStorage, log sink |
      | Data flow | labeled arrow | `-->|order JSON / HTTPS|` — label with DATA + PROTOCOL |
      | Trust boundary | `subgraph TB_x[...]` | network segment, process/user-priv change, org boundary |
      
      Rules:
      - **Label every flow with what data moves and over what channel.** Unlabeled
        arrows hide information-disclosure and tampering threats.
      - **Logs, metrics, and backups are data stores.** They hold copies of your
        assets at usually-weaker protection; draw them or you will miss the most
        common disclosure path.
      - **The attacker is not drawn; attackers are positions.** Any external entity,
        any compromised element, any element across a boundary is a potential
        attacker position.
      - **One diagram per level.** L0 context diagram (system + externals), L1 per
        service. Stop decomposing when every flow within an element is same-trust;
        decompose further when a single box contains a privilege change.
      
      ### 2. Trust boundaries — the load-bearing concept
      
      A trust boundary is any line across which the level of trust in data or
      identity changes. Draw one wherever ANY of these change:
      
      1. **Network zone** — internet → DMZ → internal → restricted.
      2. **Identity/authn** — anonymous → authenticated → admin; service A → service B
         (even "internal" services authenticate to each other or share a boundary).
      3. **Process privilege** — user-mode app → root daemon; container → host.
      4. **Organization/control** — your code → third-party SaaS, package registry,
         customer-supplied plugin, model provider.
      5. **Data validation state** — raw upload → parsed/validated object. (Parsers
         ARE boundary controls; file parsing is a boundary crossing.)
      6. **Time** — producer → queue → consumer; data written now, executed later
         (stored XSS, poisoned cache, scheduled job args). Deferred trust is still
         crossing trust.
      
      Heuristic: if compromising X gives the attacker nothing they didn't already
      have at Y, then X and Y share a boundary. If you "aren't sure" whether two
      elements share a boundary, they don't — model the crossing.
      
      ### 3. Entry points, assets, actors, privilege levels
      
      Produce these four tables for every model; they are the enumeration substrate.
      
      **Entry points** — every place external data or control enters:
      
      | ID | Entry point | Channel | Authn required | Reaches |
      |---|---|---|---|---|
      | EP1 | `POST /api/orders` | HTTPS | JWT (user) | API → DB, queue |
      | EP2 | `order.created` consumer | AMQP | broker creds (any internal producer) | worker → shipping API |
      | EP3 | Stripe webhook `/hooks/stripe` | HTTPS | signature header | API → DB |
      | EP4 | nightly `reconcile` cron | scheduler | none (implicit) | DB read/write |
      
      **Assets** — what an attacker wants; rank them:
      
      | ID | Asset | Class | Worst-case impact |
      |---|---|---|---|
      | A1 | customer PII (orders, addresses) | personal data | regulatory + churn |
      | A2 | Stripe API key | credential | financial fraud |
      | A3 | order integrity (prices, states) | business data | direct loss |
      | A4 | service availability | availability | SLA breach |
      
      Include **abstract assets**: reputation, compute (cryptomining), your users'
      trust in messages you send (phishing-from-you), and your system as a pivot
      into others.
      
      **Actors and privilege levels:**
      
      | Actor | Privilege | Notes |
      |---|---|---|
      | anonymous internet | none | reaches EP1 pre-auth surface, EP3 |
      | customer | own-tenant read/write | the IDOR baseline |
      | support agent | cross-tenant read, impersonate | high-value phish target |
      | CI pipeline | deploy + secrets | machine actor, often over-privileged |
      | `api` service account | DB rw, queue publish | blast radius if API popped |
      
      Always include **machine actors** (service accounts, CI, cron) — they hold the
      broadest standing privilege in most real systems — and at least one **insider**
      actor.
      
      ### 4. Worked mini-example — 10-line DFD with threats
      
      ```mermaid
      flowchart LR
        B[Browser] -->|creds, then session / HTTPS| W(Web API)
        S[Stripe] -->|webhook: payment event / HTTPS+sig| W
        W -->|SQL: orders, users| DB[(Postgres)]
        W -->|order.created JSON| Q[[RabbitMQ]]
        Q -->|consume| F(Fulfillment worker)
        F -->|label request / HTTPS| C[Carrier API]
        W -->|structured logs| L[(Log store)]
        subgraph TB_internet[internet]; B; S; end
        subgraph TB_backend[VPC]; W; DB; Q; F; L; end
        subgraph TB_thirdparty[third party]; C; end
      ```
      
      Boundary crossings → headline threats (full enumeration via `03` catalogs):
      - B→W: credential stuffing (S), session fixation (S), tampered order body (T).
      - S→W: forged webhook if signature unchecked or timestamp not validated —
        replay marks orders paid (S/T).
      - W→L: PII/credentials in logs — disclosure to anyone with log access (I);
        log store is a data store, modeled as such.
      - Q→F: time-shifted boundary — poisoned message executes later at worker
        privilege (T/E); broker creds shared by all internal producers = weak authn.
      - F→C: carrier creds in worker env (I); carrier outage stalls queue (D);
        response from C is untrusted input INTO F (T) — third-party responses cross
        a boundary inward too.
      
      ## B. Extracting the model from an existing codebase (AUDIT mode)
      
      Reconstruct entry points, flows, stores, and boundaries from artifacts in this
      order — code lies less than docs.
      
      ### 5. Entry-point extraction by mechanism
      
      Search patterns (adapt to stack; run broad, then verify by reading):
      
      | Mechanism | What to grep / read |
      |---|---|
      | HTTP routes | framework registrations: `@app.route|@Get\(|router\.(get|post)|http.HandleFunc|urlpatterns|#\[get\(`; OpenAPI specs; ingress/ALB rules in IaC |
      | gRPC | `.proto` files, `RegisterService`, server interceptors (authn lives here) |
      | Queue/stream consumers | `@KafkaListener|consumer|subscribe|sqs.receive|channel.basic_consume|pubsub.*subscription`; broker IaC for topic ACLs |
      | Cron/scheduled | `crontab`, k8s `CronJob`, `@Scheduled|celery beat|cloudwatch event|cloud scheduler`; note: cron handlers often skip authn entirely |
      | Webhooks (inbound) | routes named `hook|callback|notify|ipn`; verify presence of signature validation NEXT TO the route |
      | Third-party callbacks | OAuth `redirect_uri` handlers, payment IPN, SSO ACS endpoints — high-trust by design, check state/nonce/signature |
      | File ingestion | upload routes, `multipart`, S3 event triggers, watched directories, email-attachment pipelines |
      | CLI/admin | `argparse|cobra|click` entry points, `/admin` routes, debug endpoints (`/actuator|/debug/pprof|graphql introspection`) |
      | Outbound that returns | every HTTP client call site is an entry point for the RESPONSE (deserialization, SSRF-redirects) |
      
      For each hit record: path:line, authn mechanism (or none), input schema,
      downstream reach. **An entry point with no findable authn check is a finding,
      not a TODO.**
      
      Worked extraction excerpt (Flask + Terraform monorepo):
      
      ```
      $ grep -rn "@app.route\|@bp.route" services/ | wc -l        → 38 routes
      $ grep -rn "@require_auth\|@login_required" services/ | wc -l → 31 decorators
        → 7 routes to read by hand. Verdict: 4 are health/static; 2 are the
          OAuth callback + Stripe webhook (sig-checked, OK); 1 is
          services/admin/jobs.py:14 POST /internal/requeue — NO AUTH. Finding.
      $ grep -rn "basic_consume\|@celery" services/               → 5 consumers
      $ grep -rn "aws_cloudwatch_event\|CronJob" infra/           → 2 schedules
      $ grep -rn "0.0.0.0/0" infra/*.tf
        infra/sg.tf:41 ingress 5432 ← the DB is internet-reachable. Finding.
      ```
      
      The arithmetic pattern (routes minus auth decorators, then read the
      remainder) scales to any framework and is reproducible evidence for the
      audit trail (`06` §2).
      
      ### 6. Stores, flows, and assets from code
      
      - **Stores:** DB connection strings/ORM configs, S3/GCS client instantiations,
        Redis/memcached, message broker (it stores messages), log/metric sinks,
        `localStorage|document.cookie` in frontend code, mobile keychain/shared-prefs.
      - **Data classes/assets:** ORM models and migrations (column names: `email`,
        `ssn`, `dob`, `address`, `token`), secrets managers usage, `.env.example`,
        IaC secret resources. Sequential integer PKs on user-owned resources →
        enumeration risk, note it.
      - **Flows:** trace from each entry point to stores/outbound calls. For large
        codebases, trace only flows from entry points that touch top-3 assets —
        depth over breadth.
      
      ### 7. Inferring trust boundaries from an existing system
      
      - **Network:** VPC/subnet/security-group/k8s NetworkPolicy in IaC; ingress vs.
        ClusterIP services; "0.0.0.0/0" rules mark the internet boundary precisely.
      - **Identity:** where authn middleware is mounted (and which routes are
        EXCLUDED — exclusion lists are boundary holes); service-to-service auth
        (mTLS, IAM, shared static token = weak boundary); IAM policies map machine
        actors to reach.
      - **Privilege:** Dockerfile `USER`, k8s `securityContext`, sudoers, DB users
        per service (one shared `app` superuser = no internal boundaries in the data
        tier).
      - **Org:** every third-party SDK/API in lockfiles + outbound allowlists; each
        is an org boundary with its own catalog pass (`03`).
      
      Then DIFF inferred boundaries against any documented architecture: each
      mismatch (documented boundary absent in code, or real flow absent from docs)
      is itself a finding — drift is how systems rot.
      
      ### 8. Privilege-reach map (what a compromise buys)
      
      For each process and machine actor, answer: "if THIS is compromised, what can
      the attacker now reach?" One table, built from creds in env/IAM/DB grants:
      
      | If compromised | Reaches directly | Notable NOT-reach |
      |---|---|---|
      | Web API pod | orders DB rw, queue publish, Stripe key | carrier creds, CI |
      | Fulfillment worker | queue consume, carrier API, orders DB **rw** | Stripe key |
      | CI runner | deploy creds, all repo secrets, prod kubeconfig | — |
      
      This table does three jobs: exposes over-privilege at a glance (why does the
      worker have DB **write**? why does CI reach prod directly?), provides the
      impact half of every rating in `04`, and identifies where one segmentation
      control collapses multiple attack-tree branches. In audit mode it is derived
      purely from IAM policies, DB grants, and network policy — no interviews
      needed, and it rarely matches what the team believes.
      
      ### 9. Decomposition outputs
      
      A decomposition is done when you have: L0+L1 mermaid DFDs with boundaries; the
      four tables (entry points, assets, actors/privileges, stores) with code refs
      in audit mode; and a stated scope ("modeled X; excluded Y because Z"). Excluded
      scope must be written down — silent exclusions are where breaches live.
      
      ## Audit checklist
      
      - [ ] DFD exists, uses the 4-element vocabulary, every flow labeled with data
            + channel; logs/backups/caches drawn as stores.
      - [ ] Trust boundaries explicit and justified by network/identity/privilege/
            org/validation/time changes — not just "internal vs external".
      - [ ] Entry-point table covers HTTP, gRPC, queues, cron, webhooks, callbacks,
            file ingestion, admin/CLI, and third-party responses; each row has authn
            mechanism and downstream reach.
      - [ ] Every entry point in code appears in the table (grep sweep performed);
            authn-less entry points flagged.
      - [ ] Asset table ranks concrete and abstract assets; data classes derived
            from schemas, not memory.
      - [ ] Actor table includes machine actors (CI, service accounts, cron) and an
            insider; privilege per actor stated.
      - [ ] Boundaries inferred from IaC/middleware/IAM match documented
            architecture; drift recorded as findings.
      - [ ] Time-shifted crossings (queues, caches, stored content, scheduled jobs)
            modeled as boundary crossings.
      - [ ] Privilege-reach map built from actual grants (IAM/DB/network), and
            over-privilege deltas vs. need recorded.
      - [ ] Scope exclusions written down with reasons.
      
    • 03-threat-catalogs.md 18.3 KB
      # 03 — Per-Component Threat Catalogs
      
      Use these catalogs AFTER decomposition (`02`): for each component on the DFD,
      walk its catalog and emit threat sentences (*actor → action → asset → impact*)
      for every applicable item. In AUDIT mode, additionally record control
      present/partial/absent with file:line evidence (`06`).
      
      Catalogs are floors, not ceilings — they encode the threats that recur in
      practice; boundary-specific reasoning (`01` §2) finds the rest. STRIDE/LINDDUN
      letters annotate each item for classification.
      
      ## 1. Web frontend (browser-executed code)
      
      - **XSS in all variants (T/I/E):** reflected, stored, DOM-based; framework
        escape hatches (`dangerouslySetInnerHTML`, `v-html`, `innerHTML`,
        `bypassSecurityTrust*`). Stored XSS is a time-shifted boundary crossing —
        attacker content executes later in victims' sessions.
      - **CSP absent or neutered (defense-in-depth for XSS):** `unsafe-inline`,
        `unsafe-eval`, wildcard sources defeat the point. Audit the header, not the
        intent.
      - **Token storage (I/S):** long-lived tokens in `localStorage` are exfiltrable
        by any XSS; prefer httpOnly+SameSite cookies or in-memory + refresh.
      - **CSRF (S/T):** state-changing requests authenticated by cookies need
        SameSite + anti-CSRF token; JSON-only APIs still need it if cookies auth and
        content-type isn't enforced server-side.
      - **Client-side authz as the ONLY authz (E):** hidden admin menu ≠ access
        control; every privileged decision re-checked server-side.
      - **Secrets shipped in bundles (I):** API keys, internal URLs, feature-flag
        payloads — assume the bundle is public; grep build artifacts for entropy.
      - **Supply chain (T):** npm dependencies execute in your security context;
        third-party `<script>` tags execute in your origin; subresource integrity
        for CDN assets; lockfile + provenance for packages.
      - **Open redirects (S):** `?next=` params feeding `location` enable phishing
        and OAuth token theft; allowlist destinations.
      - **postMessage / iframe (S/T/I):** missing origin checks on `message`
        listeners; embedding untrusted iframes without `sandbox`; clickjacking —
        `frame-ancestors`.
      - **Sensitive data residue (I/L):** PII in URL params (logged everywhere),
        browser cache/history, analytics events, session-replay tools (LINDDUN: L,
        Dd).
      
      ## 2. API / backend service
      
      - **Broken object-level authz / IDOR (E/I):** THE top API threat. Every
        handler touching a resource by ID must verify the caller's right to THAT
        object, not just a valid session. Audit: pick 5 by-ID endpoints, find the
        tenant/owner check.
      - **Broken function-level authz (E):** admin routes guarded only by URL
        obscurity or frontend; middleware exclusion lists.
      - **Mass assignment / over-binding (T/E):** request body bound straight to
        model (`role`, `is_admin`, `price` settable). Use explicit allowlists/DTOs.
      - **Injection (T/I/E):** SQL (string-built queries), NoSQL (`$where`, operator
        injection), command (`exec` with user input), template (SSTI), LDAP, header/
        log injection (CRLF). Parameterize; treat logs as an injection sink.
      - **SSRF (S/I/E):** any user-influenced URL fetched server-side (webhook test
        buttons, importers, PDF renderers, image proxies) reaches internal services
        and cloud metadata (§9). Allowlist scheme+host+port; block link-local; re-
        resolve after redirects (DNS rebinding).
      - **Authn weaknesses (S):** JWT alg confusion / `none`, unvalidated `aud`/
        `iss`, no expiry check, symmetric key reuse across services; password reset
        token predictability; missing brute-force lockout/rate limit; session
        fixation.
      - **Unsafe deserialization (T/E):** pickle/Java serialization/`yaml.load` on
        external data = RCE primitive. Treat serialized blobs as code.
      - **Excessive data exposure (I):** returning full ORM objects and filtering
        client-side; verbose errors with stack traces/SQL; GraphQL introspection +
        unbounded query depth/aliases (also D).
      - **Rate limiting & resource caps (D):** per-principal limits on authn
        endpoints, expensive queries, pagination (`?limit=10000000`), regex on user
        input (ReDoS), zip/XML expansion (bombs, XXE — also I).
      - **Repudiation (R):** security-relevant actions (login, authz failure,
        privilege change, data export) logged with actor + object + outcome, to a
        store app credentials can't rewrite.
      - **Internal trust (S/E):** "internal" services accepting unauthenticated
        calls — anyone with SSRF or a foothold is "internal".
      
      ## 3. Database / data tier
      
      - **Shared superuser account (E):** every service connecting as one privileged
        user = no internal boundaries; per-service users, least privilege, no DDL at
        runtime.
      - **Network exposure (S/I):** DB reachable beyond its app subnet; public IPs
        on managed DBs; no TLS on connections.
      - **Encryption (I):** at-rest (and: who holds the key — disk encryption
        doesn't stop SQL-level theft); field-level for crown jewels (tokens, SSNs)
        so a SQLi/backup leak yields ciphertext.
      - **Backups & replicas (I):** backups inherit none of prod's access controls
        by default — encrypted? access-logged? tested restore? Read replicas with
        weaker creds; snapshots shared cross-account.
      - **Row-level isolation (E/I):** multi-tenant tables relying solely on app
        WHERE clauses; consider RLS as a second layer for high-value tenancy.
      - **Audit & repudiation (R):** DDL/DCL and bulk-read logging; who watches
        `SELECT *` of the users table?
      - **Retention & privacy (LINDDUN Dd/Nc):** retention enforced (TTL/jobs), data
        deletion actually deletes (incl. backups policy), purpose-bound copies (no
        prod PII in staging/analytics without masking).
      - **ORM truths (T):** raw query escape hatches (`.raw(`, `text(`,
        `query_string`) carry injection risk audits often skip.
      
      ## 4. Message queue / event stream
      
      A queue is a **time-shifted entry point**: consumers execute attacker-era data
      in a later, often more privileged context.
      
      - **Producer authn/authz (S):** can any internal workload publish to any
        topic? Shared broker creds = any compromised pod forges any event. Per-
        service credentials + topic ACLs.
      - **Message integrity & schema (T):** consumers validate schema + business
        invariants (price ≥ 0, state transitions legal); never trust
        producer-supplied identity fields — derive actor from broker auth or signed
        envelope.
      - **Confused-deputy consumers (E):** consumer acts at high privilege on
        low-trust data ("delete-user" event with attacker-chosen ID). Re-check
        authorization at consumption time, not just production time.
      - **Poison messages & retries (D):** malformed message crash-looping a
        consumer stalls the partition; DLQ + max retries; idempotency keys (replay =
        duplicate side effects — payments!).
      - **Disclosure (I):** queues persist PII/secrets in payloads; broker at-rest
        encryption, payload minimization (send IDs not blobs), DLQ contents are an
        unmonitored data store of your worst messages.
      - **Ordering/race abuse (T):** logic depending on event order an attacker can
        influence (cancel-after-ship races, double-spend via concurrent consumers).
      - **Repudiation (R):** event provenance — which principal produced this
        message, traceable end to end?
      
      ## 5. File storage / upload pipelines
      
      - **Content-type laundering (T/E):** trust magic bytes + re-encode, never the
        client `Content-Type` or extension; SVG is XSS, HTML upload + same-origin
        serving = stored XSS; polyglot files.
      - **Parser attack surface (E/D):** image/PDF/office parsers are RCE farms —
        sandbox/isolate parsing workers (separate service, no creds, egress-deny);
        decompression bombs; XML in office docs → XXE.
      - **Path traversal (T/I):** user-influenced filenames/keys (`../`, absolute
        paths, unicode normalization); generate server-side names, map via DB.
      - **Serving (I/E):** serve user content from a separate origin/domain (cookie
        isolation); signed URLs with short expiry; no public-listable buckets (§9);
        `Content-Disposition` + `X-Content-Type-Options: nosniff`.
      - **Authorization (E/I):** signed-URL leakage via referer/logs; per-object
        authz on download endpoints (file IDOR is as common as API IDOR).
      - **Malware relay (abstract asset):** your storage distributing malware to
        other users — scanning or risk-acceptance, stated either way.
      - **Quota (D):** per-user size/count caps; multipart abandonment cleanup.
      
      ## 6. CI/CD & build pipeline
      
      The pipeline holds deploy creds and shapes every artifact — it is usually the
      highest-privilege, least-modeled component.
      
      - **Poisoned pipeline execution (T/E):** PRs from forks executing privileged
        workflows; `pull_request_target` + checkout-of-PR-head; injectable
        expressions (`${{ github.event.issue.title }}` in `run:`); pipeline config
        editable by the same PR it gates.
      - **Secrets exposure (I):** long-lived cloud keys in CI secrets vs. OIDC
        federation; secrets readable by all repo collaborators; secret-echo via
        `set -x`/debug logs; cache poisoning across trust levels (PR cache reused by
        main builds).
      - **Dependency/supply chain (T):** lockfiles + integrity hashes enforced in
        CI; dependency confusion (internal package names registered publicly,
        registry order); install scripts execute at build privilege; typosquats;
        base-image provenance and pinning by digest.
      - **Artifact integrity (T):** signed artifacts/provenance (SLSA-style) so prod
        runs what CI built; deploy step verifies signature; who can push to the
        registry directly, bypassing CI?
      - **Runner trust (E):** self-hosted runners on shared infra = lateral
        movement; ephemeral runners; runner reach into prod networks.
      - **Branch protection as a security control (T/R):** force-push/admin-bypass
        on release branches; required reviews on workflow files specifically; audit
        trail of who approved what.
      - **Environment promotion (E):** can staging creds deploy to prod? Separate
        identities per environment.
      
      ## 7. Mobile clients
      
      - **The app binary is public (I):** secrets/API keys in the app are
        extracted — assume so; per-user tokens only; server-side checks for
        everything (client is UI, never enforcement).
      - **Local storage (I):** tokens/PII in Keychain/Keystore, not plist/
        shared-prefs/SQLite plaintext; OS backups capture app data — mark exclusions.
      - **Transport (S/I):** TLS everywhere + pinning for high-value apps (with a
        rotation story); user-installed CA threat for sensitive verticals.
      - **Deep links / app links (S/T):** unvalidated deep-link params hitting authn
        actions; link hijacking (claim verified app links); OAuth redirect via
        custom scheme is interceptable — use PKCE always.
      - **IPC surface (E):** exported Android components (activities/receivers/
        providers) — audit the manifest; iOS URL schemes and extensions.
      - **WebView (T/E):** JS bridges (`addJavascriptInterface`) exposing native
        functions to loaded content; loading remote content in privileged WebViews.
      - **Reverse engineering & tamper (T):** root/jailbreak + repackaging for
        client-trusting apps (games, payments); attestation (Play Integrity/App
        Attest) as mitigation where the business case warrants.
      - **Privacy (LINDDUN):** device identifiers enabling cross-app linking (L/I);
        analytics SDKs shipping PII (Dd/U); permissions minimal (U).
      
      ## 8. LLM agent / tool-use systems
      
      Model the LLM as a **confused-deputy-prone process whose control plane and
      data plane are the same channel**. Every token the model reads is potentially
      instructions. Companion catalogs: OWASP LLM Top 10 and the OWASP Top 10 for
      Agentic Applications 2026 (ASI01–ASI10: goal hijack, tool misuse, identity/
      privilege abuse, agentic supply chain, unexpected code execution, memory
      poisoning, inter-agent comms, cascading failures, human-trust exploitation,
      rogue agents) — the items below cover them; use ASI numbering when reporting.
      
      - **Direct prompt injection (S/T):** user input overriding system intent.
        System prompts are not a security boundary — assume full disclosure of the
        prompt (I) and design so that prompt knowledge gains nothing.
      - **Indirect prompt injection (S/T/E) — the defining threat:** instructions
        embedded in retrieved web pages, RAG documents, emails, tickets, tool
        outputs, repo files. Any agent that (a) reads attacker-influenceable content
        AND (b) has tools with side effects is exploitable by default. Enumerate
        every content source on the DFD as a hostile entry point.
      - **Excessive agency (E):** tool scope beyond the task (agent with `send_email`
        + `read_all_docs` = exfiltration machine). Least-privilege tools: per-task
        allowlists, read-only by default, scoped credentials per invocation, human
        confirmation gates on irreversible/external actions (payments, deletes,
        sends, code execution).
      - **Exfiltration via outputs (I):** injected instructions encode secrets into
        markdown image URLs, links, or tool parameters. Mitigate: egress allowlists,
        render-time URL sanitization, no auto-fetch of model-emitted URLs.
      - **Tool-call injection (T/E):** model-generated arguments flowing into
        SQL/shell/URLs — tool implementations must validate args exactly like an
        internet-facing API (the model is an untrusted caller).
      - **Cross-tenant leakage in RAG (I/E):** retrieval must enforce the CALLER's
        ACLs at query time — embeddings stores rarely carry authz natively.
      - **Multi-agent / MCP trust (S/T):** third-party tool servers and agent cards
        are org-boundary crossings; tool descriptions themselves can carry
        injections; pin/verify tool definitions.
      - **Named MCP attack classes (T/S/E)** — enumerate per attached server; use
        these names in findings (OWASP MCP Top 10 MCP03:2025; MITRE ATLAS
        AML.T0104); mitigations detailed in sota-code-security rules/08 §5:
        - *Tool poisoning:* hidden instructions in tool descriptions/metadata →
          violates the instruction/data boundary → pin + human-review full
          definitions at install.
        - *Rug pull:* tool definition/behavior changes after approval → violates
          the approval's integrity over time → hash-pin definitions, re-approve on
          change.
        - *Tool shadowing:* one server's descriptions steer use of ANOTHER server's
          tools → violates inter-server isolation → separate sessions/agents for
          high-privilege tools.
        - *Line jumping:* injection at `tools/list`, before any call → bypasses
          invocation-time gates → treat listings as untrusted; review before
          connecting.
        - *Preference manipulation (MPMA):* manipulative descriptions bias tool
          selection toward attacker servers → violates selection integrity →
          allowlisted servers + description review.
      - **Reasoning-model attacks (S/D):** CoT hijacking / H-CoT — untrusted text
        posing as the model's own reasoning steers safety/tool decisions (S);
        OverThink-class decoys in retrieved content force excessive reasoning
        tokens — cost/latency exhaustion (D). Cap reasoning budgets; keep untrusted
        content out of reasoning scaffolds (sota-code-security rules/08 §5).
      - **Memory/state poisoning (T):** persisted conversation memory or scratchpads
        let an injection survive across sessions and users.
      - **DoS / cost (D):** unbounded agent loops, token-expensive inputs, recursive
        tool calls — cap steps, tokens, spend per request.
      - **Privacy (LINDDUN):** prompts/completions logged with PII (Dd); user data in
        fine-tuning/eval sets (Nc); provider data-retention terms (org boundary).
      - **Mitigation pattern:** dual-LLM / plan-then-execute (planner sees untrusted
        content, executor with tools sees only structured plan), or taint-tracking:
        once untrusted content enters context, downgrade available tools for the
        rest of the session.
      
      ## 9. Cloud-specific threats (cross-cutting)
      
      - **IAM misconfig (E):** wildcard actions/resources (`"Action":"*"`);
        privilege-escalation primitives (`iam:PassRole` + `*:Create*`,
        `iam:PutUserPolicy`, `sts:AssumeRole` trust policies open to broad
        principals); unused-but-live credentials; no permission boundaries on CI
        identities. Audit IaC, not the console.
      - **Metadata service / credential theft (I/E):** SSRF → `169.254.169.254` →
        role creds (the canonical cloud kill chain). Enforce IMDSv2/hop-limit=1 (or
        GCP metadata header), block link-local egress from app containers, minimal
        instance roles.
      - **Public buckets/storage (I):** bucket policy + ACL + account-level
        public-access-block all checked; "authenticated users" ≠ "my users"; listable
        buckets enumerate keys; same for public snapshots/AMIs/container registries.
      - **Cross-account trust (S/E):** resource policies (S3, KMS, SNS, Lambda)
        granting external accounts; confused deputy without `ExternalId`/source-arn
        conditions.
      - **Secrets sprawl (I):** secrets in env vars visible to whole task/pod, in
        IaC state files (state bucket protection!), in container layers, in Lambda
        env config readable by `lambda:GetFunction`.
      - **Logging/detection (R):** control-plane audit logs (CloudTrail-class) on,
        immutable, alarmed for IAM changes and impossible-travel; flow logs at
        boundaries you claimed in the model.
      - **Serverless/managed (E/D):** function resource policies (who can invoke),
        event-source injection (S3 key names, SNS payloads as untrusted input),
        concurrency limits as DoS containment.
      
      ## Audit checklist
      
      - [ ] Every DFD component mapped to its catalog; each item dispositioned
            (present/partial/absent/N-A) — no silent skips.
      - [ ] Frontend: XSS sinks audited, CSP effective, token storage justified,
            CSRF covered, no secrets in bundles.
      - [ ] API: object-level authz verified on sampled by-ID endpoints; mass
            assignment, SSRF, deserialization, and rate limits checked with code
            evidence.
      - [ ] Database: per-service least-priv users, encryption + key custody,
            backup/replica protections, retention enforcement.
      - [ ] Queues: producer authn, schema validation at consumers, authz re-check
            at consumption, idempotency, DLQ handling.
      - [ ] File pipeline: magic-byte validation, parser isolation, traversal-proof
            naming, separate serving origin, download authz.
      - [ ] CI/CD: fork-PR privilege, OIDC over static keys, lockfile enforcement,
            artifact signing, workflow-file review protection, runner isolation.
      - [ ] Mobile: no embedded shared secrets, Keychain/Keystore usage, PKCE,
            exported-component audit, WebView bridge audit.
      - [ ] LLM/agent: every content source treated as hostile, tool least-
            privilege + confirmation gates, output URL handling, RAG ACL
            enforcement, step/spend caps.
      - [ ] Cloud: IAM wildcards and escalation primitives, IMDSv2/metadata
            protection, public-access blocks, cross-account conditions, audit-log
            immutability.
      
    • 04-risk-rating-treatment.md 12.3 KB
      # 04 — Risk Rating & Treatment
      
      Rating exists to ORDER work and justify dispositions — not to produce
      precise-looking numbers. Prefer a coarse, calibrated, contextual scale applied
      consistently over a fine-grained scale applied inconsistently.
      
      ## 1. DREAD — know it, and know why not to trust it
      
      DREAD scores Damage, Reproducibility, Exploitability, Affected users,
      Discoverability (1–10 each, averaged). Pitfalls — each one disqualifying for
      serious use:
      
      1. **Unanchored scales.** "Damage = 7" means different things to different
         raters; scores drift by who's in the room. (Microsoft itself dropped DREAD
         for this.)
      2. **Averaging hides extremes.** Damage 10 / everything-else 2 averages to a
         "low" — but a hard-to-find RCE is still an RCE. Worst-dimension logic
         beats means.
      3. **Discoverability rewards obscurity.** Rating threats lower because
         "nobody will find it" institutionalizes security-by-obscurity; attackers
         read code, run scanners, and get lucky. If you keep D, score it 10 always —
         at which point drop it.
      4. **Double counting.** Reproducibility, Exploitability, Discoverability are
         three blurry views of likelihood; one inflated dimension skews the total.
      
      If an org mandates DREAD: anchor every level with written exemplars, replace
      the mean with max-of(Damage, weakest-link likelihood), and fix D=10. At that
      point you have rebuilt likelihood × impact — use that directly (§3).
      
      ## 2. CVSS — what it's for and how to use it without lying
      
      CVSS scores **vulnerability severity characteristics**, not your risk. Base
      score assumes a "reasonable worst case" deployment that is not yours.
      
      Rules:
      - **Use CVSS for vulnerabilities (CVEs, pentest findings), not design-stage
        threats.** Threats from a model lack the concrete exploit parameters CVSS
        vectors encode; scoring hypotheticals produces false precision.
      - **Never rank by base score alone.** Adjust with environmental/threat
        metrics — or informally: Is the vulnerable path reachable here? Authn in
        front? Exploit public? Asset behind it valuable? A 9.8 in a dev-only,
        network-isolated tool can be Medium; a 6.5 authz bypass on the payment API
        is Critical.
      - **Record the vector string, not just the number** (e.g.
        `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H`) so reviewers can audit the
        assumptions — the vector is the rating; the number is a summary.
      - **Note the version prefix.** CVSS v4.0 (the current spec, 2023) replaced
        temporal metrics with threat metrics (CVSS-B/BT/BTE nomenclature); v3.1 and
        v4.0 scores coexist in feeds — the prefix says which rules produced the
        number, so never compare scores across versions.
      - **CVSS ≠ exploitation probability.** For "will this actually be exploited",
        consult exploit-prediction signals (EPSS-class scores, KEV-style
        known-exploited lists) and your own exposure; severity and likelihood are
        separate axes.
      
      ## 3. Likelihood × impact — the default rating method
      
      Use a 3×3 (or at most 4×4) matrix with ANCHORED level definitions. Anchors are
      the whole method; publish them with the model.
      
      **Likelihood anchors** (calibrate to your exposure):
      
      | Level | Anchor |
      |---|---|
      | High | Exploitable by an unauthenticated or any-customer actor with public techniques/tools; or attack is automated/commodity (credential stuffing, scanner-findable) |
      | Medium | Needs a valid account, a specific misconfig, social engineering, or chaining two weaknesses; technique documented but targeted |
      | Low | Needs insider access, physical access, significant novel research, or multiple independent failures |
      
      **Impact anchors** (write per system, in business terms — PASTA-lite preamble
      from `01` §4 feeds this):
      
      | Level | Anchor (example for a payments SaaS) |
      |---|---|
      | High | Any-customer data breach; money movement; RCE in prod; full account takeover class |
      | Medium | Single-account compromise; partial data exposure; sustained outage of a paid feature |
      | Low | Cosmetic, single-user self-inflicted, info of negligible value |
      
      **Matrix → priority:**
      
      | | Impact Low | Impact Med | Impact High |
      |---|---|---|---|
      | **Likelihood High** | Medium | High | Critical |
      | **Likelihood Med** | Low | Medium | High |
      | **Likelihood Low** | Low | Low | Medium* |
      
      \* Escalate Low×High to High when the impact is catastrophic-irreversible
      (safety, signing-key theft) — fat tails don't average.
      
      Rules:
      - **Rate the threat AS MITIGATED TODAY,** then optionally note inherent (un-
        mitigated) risk. Ranking inherent risk floods the top band uselessly.
      - **Likelihood follows the easiest path** to the impact, not the path you
        enumerated first. Attack trees (`01` §5) find the cheapest branch.
      - **Don't multiply made-up numbers.** 1–5 scales multiplied give 1–25
        pseudo-precision; band labels resist abuse better. For real quantification
        use a FAIR-style analysis with ranges — only worth it for top-5 enterprise
        risks.
      - **Calibrate across raters:** score 5 threats independently, compare, refine
        anchors where raters diverged. Re-calibrate when the team changes.
      
      Severity-label conventions for audit findings are defined in `SKILL.md` and
      elaborated in `06` — same axes, evidence-backed.
      
      ## 4. Treatment: accept / mitigate / transfer / avoid
      
      Every threat gets exactly one disposition, recorded with the threat. "Noted"
      or an unassigned ticket is not a disposition.
      
      | Treatment | Use when | Required record |
      |---|---|---|
      | **Mitigate** | Control is cheaper than expected loss; default for High+ | Requirement ID(s) + owner + verification test (§5) |
      | **Accept** | Residual risk below appetite; cost of control exceeds it | Named individual owner (a person with authority over the asset, not "the team"), rationale, expiry/review date. Un-expiring acceptances are how risk registers rot. |
      | **Transfer** | Liability shiftable: insurance, payment processor, managed service | Contract/SLA reference + the residual you keep (reputation never transfers; breach-response duties rarely do) |
      | **Avoid** | Feature/design not worth its risk | Design change record — e.g., don't store PANs at all (use a token vault), drop the "fetch any URL" feature, remove the agent's write-tools |
      
      Rules:
      - **Avoid is underused.** Always ask "can we not have this data/feature/
        privilege?" before designing a mitigation — deleted attack surface needs no
        patching. Data minimization is risk avoidance (and LINDDUN Dd treatment).
      - **Mitigations can change likelihood OR impact — say which.** Rate limiting
        cuts likelihood; encryption + tokenization cut impact; segmentation cuts
        blast radius. Prefer one impact-cutting control plus one likelihood-cutting
        control on Critical paths (defense in depth, but bounded — two layers,
        justified, not five vague ones).
      - **Acceptance escalates with severity:** Low — tech lead; Medium —
        eng manager; High — director/CISO; Critical — not acceptable without
        executive sign-off and a dated remediation plan.
      
      ## 5. Mapping mitigations to requirements and tests
      
      A mitigation that is not a requirement will not be built; a requirement that
      is not a test will not survive refactoring.
      
      **Chain:** threat → requirement → implementation → verification. Keep IDs
      linked end to end:
      
      ```
      T-012  (High) Authenticated customer reads other tenants' orders via
             GET /orders/{id} (IDOR; STRIDE-E/I)
      SR-104 Every order access MUST verify order.tenant_id == caller.tenant_id
             at the data-access layer (not per-handler).
      IMPL   OrderRepository.get() takes tenant from auth context; handlers
             cannot pass tenant explicitly. (PR #482)
      VER-1  Integration test: tenant-A token + tenant-B order id → 404.   [abuse case]
      VER-2  Static check: CI greps for OrderRepository bypass / raw order
             queries outside the repository module.                        [regression guard]
      ```
      
      Rules:
      - **Write requirements as testable MUSTs** with a location ("at the
        data-access layer"), not aspirations ("handle authz properly"). One
        requirement may cover many threats; never the reverse without splitting.
      - **Every mitigated High+ threat gets a VER entry** — an abuse-case test
        (negative test from the attacker's perspective, see `05` §3) and, where
        possible, a structural guard (lint rule, policy-as-code, dependency rule)
        that fails CI on regression.
      - **Requirements live in the backlog with normal tracking** (see `05` §2) —
        a threat model PDF with embedded TODOs is a graveyard.
      
      ## 6. Residual risk documentation
      
      After treatment, what risk remains — because controls are partial, accepted,
      or transferred-with-remainder? Document per threat, one line:
      
      ```
      T-012 residual: tenant check enforced in repository layer; raw-SQL
      escape hatches remain in /reports module (compensated by VER-2 grep,
      reviewed quarterly). Residual rating: Low. Owner: j.doe. Review: 2026-09.
      ```
      
      Rules:
      - **Residual rating uses the same L×I matrix** — re-rate after controls, don't
        hand-wave "lower".
      - **Aggregate residuals roll up to a risk register** (one table: threat ID,
        residual rating, owner, review date) — this is the artifact leadership
        actually reads; keep it under a page.
      - **An expired review date flips the acceptance to a finding** in audits
        (`06`). Build the expiry sweep into the living-model cadence (`05` §4).
      
      ## 7. Rating anti-patterns (rejected on sight in review)
      
      - **Severity haggling by remediation cost.** "Let's call it Medium because the
        fix is hard" — cost belongs in the treatment decision (maybe you accept or
        phase it), never in the rating. Once cost leaks into severity, the register
        stops describing reality.
      - **Best-case likelihood.** Rating "Low because our WAF probably blocks it" —
        rate against the easiest path WITH evidence of the control; "probably" means
        the control is Partial and the rating stands.
      - **Impact capped at the component.** "Only the worker is compromised" —
        impact follows the privilege-reach map (`02` §8), not the initially-popped
        box. A worker with DB write is a database compromise.
      - **Stale ratings after architecture change.** L×I was assigned when the
        service was internal; it's public now. Re-rating is part of every re-model
        trigger (`05` §4), not a separate ceremony.
      - **One number for a threat class.** "XSS: High" — each instance rates on its
        own context (what the page can reach, who views it). Classes get thematic
        findings (`06` §4); instances get ratings.
      - **Risk-appetite fog.** Accept/mitigate thresholds undefined, so every
        dispute is relitigated. Write the appetite line once ("we mitigate all
        High+, accept Medium with director sign-off, batch Lows quarterly") and
        point at it.
      - **Probability theater.** "0.3 likelihood × $2.4M = $720k expected loss"
        built on gut numbers. Either do the FAIR-style estimation with calibrated
        ranges and document the basis, or keep honest bands.
      
      ## Worked micro-example — rating in context
      
      Same vulnerability, two ratings, both correct:
      
      - *Unauthenticated SSRF in PDF renderer; renderer pod has IMDSv2 enforced,
        egress-deny netpol, no cloud role.* Likelihood High, Impact Low (reaches
        nothing) → **Medium**, mitigate via URL allowlist; accept residual Low.
      - *Same SSRF; pod runs with node's instance role, flat VPC.* Likelihood High,
        Impact High (metadata creds → account) → **Critical**: fix the egress/IMDS
        posture (impact cut) AND the SSRF (likelihood cut); nothing acceptable here.
      
      The CVE/base score would be identical for both. Context is the rating.
      
      ## Audit checklist
      
      - [ ] A single, anchored rating scheme is defined and used consistently;
            anchors written down, not folklore.
      - [ ] No raw DREAD means or unadjusted CVSS base scores used as priority;
            CVSS vectors recorded where CVSS is used.
      - [ ] Threats rated as-mitigated, with likelihood reflecting the easiest
            path; Low×catastrophic escalated, not averaged away.
      - [ ] Every threat has exactly one disposition: mitigate/accept/transfer/
            avoid; no "noted"/orphaned threats.
      - [ ] Acceptances have a named individual owner, rationale, and unexpired
            review date; acceptance authority matches severity.
      - [ ] "Avoid" considered (data/feature/privilege removal) before expensive
            mitigations — evidence in at least one disposition.
      - [ ] Threat→requirement→test ID chain intact for all High+ mitigations;
            abuse-case tests exist and run in CI.
      - [ ] Residual risks re-rated on the same scale and rolled into a ≤1-page
            register with owners and review dates.
      - [ ] Expired acceptances/reviews flagged as findings.
      
    • 05-outputs-operationalization.md 12.1 KB
      # 05 — Outputs & Operationalization
      
      A threat model's value is measured by the controls it ships and the
      regressions it catches — not by the document. This file defines the artifacts
      and the machinery that keeps them alive.
      
      ## 1. The threat model document — template
      
      Keep it short enough to re-read at every trigger (target: 2–6 pages / one
      markdown file in-repo). Store it NEXT TO THE CODE (`docs/threat-model.md` or
      per-service), versioned in git — review-diffable, blame-able, findable.
      
      ```markdown
      # Threat Model: <system/service> — v<NN>
      Owner: <tech lead>   Last full review: <date>   Methodologies: STRIDE-per-interaction (+LINDDUN)
      
      ## 1. Scope & business context
      What is modeled, what is explicitly excluded and why. 3 sentences on what
      the business loses if this system fails (feeds impact anchors, see 04 §3).
      
      ## 2. System model
      L0/L1 mermaid DFDs with trust boundaries (02). Tables: entry points,
      assets (ranked), actors/privilege levels, data stores.
      
      ## 3. Assumptions
      Numbered, falsifiable: "A1: broker is reachable only inside the VPC",
      "A2: provider X does not train on our data (contract §4)". Every assumption
      is a standing threat if false — audits test these first.
      
      ## 4. Threats & dispositions
      | ID | Threat (actor→action→asset→impact) | Class | L | I | Rating | Disposition | Req IDs | Residual |
      One row per threat. This table IS the model; everything else is support.
      
      ## 5. Security requirements
      SR-IDs with testable MUST statements + verification refs (04 §5).
      
      ## 6. Risk register (residuals & acceptances)
      | Threat | Residual | Owner | Review date |   ≤ 1 page (04 §6).
      
      ## 7. Re-model triggers & history
      The trigger list for THIS system + changelog of revisions and what prompted
      them.
      ```
      
      Rules:
      - **The threat table is the contract.** Reviews approve rows, not prose.
        If a section doesn't change a row, cut it.
      - **Diagrams as code** (mermaid in markdown): diffable in PRs, no stale Visio
        exports. A diagram that can't be updated in the same PR as the code change
        will drift.
      - **Write assumptions you'd bet against.** "We assume input is validated
        upstream" is the most breached assumption in distributed systems; naming it
        makes it auditable.
      
      ## 2. Security requirements backlog
      
      - **Requirements enter the same backlog as features** — same tracker, same
        refinement, same definition of done. A separate "security spreadsheet" is
        where requirements go to die.
      - **Tag and link:** label `security`, link to threat ID and model version.
        Priority comes from the threat rating (04 §3): Critical-derived requirements
        block the release that introduces the threat; High within the sprint/cycle;
        Medium scheduled; Low backlog with review date.
      - **Acceptance criteria = the verification entry.** A security story is done
        when the abuse-case test passes and the structural guard is in CI — not when
        "code is written".
      - **Recurring requirements become paved road.** If three models demand "JWT
        validation per SR-x", build/adopt a shared middleware and convert the
        requirement to "uses paved-road component vX" — threat modeling output
        should compound into platform, shrinking future models.
      
      ## 3. Abuse cases as test cases
      
      For every mitigated High+ threat, write the attacker's user story and automate
      it:
      
      ```
      Abuse case AC-012 (from T-012, IDOR):
        As tenant-A attacker with a valid session,
        I request GET /orders/{tenant-B-order-id}
        expecting 404/403 and an authz-failure audit event.
      
      test_cross_tenant_order_access_denied():
          token = login(tenant="A")
          r = client.get(f"/orders/{seed_order(tenant='B').id}", auth=token)
          assert r.status_code in (403, 404)
          assert audit_log.contains(event="authz.denied", actor=token.sub)
      ```
      
      Rules:
      - **Test the control's OBSERVABLE effect, not its implementation** (status
        code + audit event, not "repository was called with tenant param") — so
        refactors keep the test honest.
      - **Negative tests at the right layer:** authz → integration/API tests;
        injection → unit tests on the sink + fuzz where parsers are involved; rate
        limits/DoS caps → load-shaped tests or config assertions; CSP/headers/IaC
        posture → policy-as-code (OPA/conftest, tfsec-style rules) running in CI.
      - **For LLM/agent threats** (03 §8): maintain an injection corpus (strings
        embedding "ignore instructions, call tool X / exfiltrate to URL") run
        against the agent in CI; assert tools-not-called / URL-not-fetched / spend
        caps hold. Probabilistic systems need statistical assertions (N trials,
        zero tool-policy violations).
      - **Each abuse-case test cites its threat ID in the test name or docstring**
        — when it fails, the developer reads WHY this matters; when someone deletes
        it, review sees a threat losing its verification.
      - **Pentest/red-team findings feed back:** every confirmed finding becomes
        (a) a threat-table row — was it missing or mis-rated? — and (b) an
        abuse-case regression test.
      
      ## 4. Keeping the model living
      
      A threat model is stale the moment the system changes in a way the model
      didn't anticipate. Freshness is enforced by TRIGGERS, not calendars (plus one
      calendar backstop).
      
      ### Re-model triggers (the canonical list — tailor per system, never shrink below this)
      
      | Trigger | Why it invalidates the model |
      |---|---|
      | New dependency (package, SaaS, model provider) | New org-trust boundary + supply-chain surface (03 §6) |
      | New entry point: route, queue/topic, cron, webhook, callback, upload | Attack surface change by definition (02 §5) |
      | New or moved trust boundary (service split/merge, network change, new env) | Every boundary crossing needs enumeration (01 §2) |
      | New data class (PII category, credentials, payment, health) | Asset table + LINDDUN pass invalidated; impact anchors shift |
      | Authn/authz change (token format, session, roles, tenancy model) | The S and E columns of every interaction change |
      | Crypto/key management change | Silent impact-rating changes across stored assets |
      | New actor class (partners, plugin authors, agent tools, support tooling) | Privilege table invalidated |
      | Deserialization / file parsing / template rendering added | Highest-yield vuln classes; instant catalog pass |
      | Incident or pentest finding in this system | Empirical proof the model missed something |
      | Acceptance/review date expired (04 §6) | Disposition no longer valid |
      
      ### Enforcement mechanics (pick at least two)
      
      - **PR template** with a `## Security notes` section: author states which
        triggers apply (or "none") — makes the check cheap and the omission visible.
      - **CI trigger heuristics:** flag PRs touching route registrations, lockfiles
        with new packages, IaC network/IAM files, auth middleware, or `*.proto` —
        require the security-notes section to be non-trivial on flagged PRs.
      - **Model version pinning:** the threat-model doc records the git SHA range it
        covers; an audit (06) compares triggers-since-SHA against model revisions.
      - **Calendar backstop:** full re-read annually or per major version,
        WHICHEVER COMES FIRST with trigger-driven updates — the backstop catches
        slow drift (dependency rot, team turnover, assumption decay).
      
      ### Incremental update discipline
      
      - Trigger fires → update only the affected rows/diagram region + bump model
        version with a one-line changelog ("v12: added Stripe webhook EP3, threats
        T-031..034"). Full rewrites are for re-architecture only.
      - **Deleting is updating:** removed features must remove threats/requirements,
        or the model accretes noise until nobody reads it. Dead rows are marked
        `retired (vNN)`, kept one version for the diff, then dropped.
      - New team members onboard by READING the threat model before the code —
        if that's not useful, the model has failed its second purpose
        (knowledge transfer), fix it.
      
      ## 5. PR security-notes template (paste into PR template)
      
      ```markdown
      ## Security notes
      Triggers touched: [ ] new dependency  [ ] new entry point  [ ] trust boundary
      [ ] new data class  [ ] authn/authz  [ ] crypto  [ ] parsing/deserialization
      [ ] none
      New input → from whom: ...
      Runs at privilege → can now reach: ...
      Writes/emits/calls (incl. logs, third parties): ...
      At 1000× volume / 100MB payload: ...
      Threat model updated? <link/version or "no triggers">
      ```
      
      A filled template takes 3 minutes for "none" and ~10 when triggers fire; it
      gives reviewers a fixed place to look and auditors (`06`) a drift signal.
      Reject "N/A" without the checkbox rationale — the box list IS the rationale.
      
      ## 6. Threat-model review session format (when a workshop IS warranted)
      
      For new services, new trust boundaries, or escalations from a four-questions
      pass. 60–90 minutes, hard cap; 3–6 people: feature owner, one engineer who
      did NOT write the design, security (if available), someone who runs prod.
      
      1. (10 min) Owner walks the DFD; attendees attack the DIAGRAM first — missing
         flows, unlabeled arrows, "where does the webhook actually land?" Fixing
         the model is cheaper than fixing threats against the wrong model.
      2. (35 min) Per boundary crossing, STRIDE prompts; scribe writes threat
         sentences directly into the table — no minutes, no slides.
      3. (15 min) Rate and disposition in-session for everything captured; assign
         requirement owners. Undispositioned threats don't leave the room.
      4. (5 min) Confirm re-model triggers and the model owner.
      
      Rules: the design's author never scribes (they defend instead of capture);
      "that's already handled" requires naming WHERE (file/control) or the threat
      stays; park exploit-tactics rabbit holes after 2 minutes — enumeration
      breadth beats depth here.
      
      ## 7. Program health metrics (measure the machinery, not threat counts)
      
      Track quarterly, per service:
      
      | Metric | Healthy signal | Smell |
      |---|---|---|
      | Trigger compliance | % trigger-matching PRs with non-trivial security notes ≥ 90% | template rubber-stamped "none" on PRs adding routes |
      | Model freshness | days since last revision < days since last trigger-matching merge | model older than the current architecture |
      | Verification coverage | % High+ mitigations with passing abuse-case tests = 100% | requirements "done" with no VER link |
      | Acceptance hygiene | 0 expired review dates | acceptances from departed owners |
      | Escape rate | incidents/pentest findings that existed as un-actioned model rows | model knew, backlog buried it — a prioritization failure, fix the rating pipeline not the model |
      
      Do NOT manage to "number of threats found" — it incentivizes noise and
      punishes good design. Escape rate is the only outcome metric that matters.
      
      ## 8. Output sizing — match artifact to audience
      
      | Audience | Artifact | Size |
      |---|---|---|
      | Engineers (daily) | threat table + requirements in repo | the source of truth |
      | Reviewers (per PR) | security-notes section | 3–10 lines |
      | Leadership (quarterly) | risk register | ≤ 1 page |
      | Auditors/customers | the doc (template §1) + evidence links | 2–6 pages |
      
      Never produce the 40-page monolith: it satisfies no audience and updates
      never. Generate views from the threat table instead.
      
      ## Audit checklist
      
      - [ ] Threat model exists in-repo, versioned, with owner and last-review date;
            follows (or maps cleanly onto) the template sections.
      - [ ] The threat table has L/I/rating/disposition/requirement-ID columns
            filled for every row; no prose-only threats.
      - [ ] Assumptions are explicit, numbered, and individually testable; spot-
            check 2–3 against reality (network reachability, contract terms).
      - [ ] Security requirements live in the team's actual backlog with threat-ID
            links and rating-derived priority — not a side spreadsheet.
      - [ ] Every mitigated High+ threat has an automated abuse-case test citing
            its threat ID; tests assert observable effects and run in CI.
      - [ ] Posture controls (headers, IaC, IAM) covered by policy-as-code checks,
            not manual review notes.
      - [ ] Re-model trigger list documented for this system; PR template or CI
            heuristics enforce it; sample 5 trigger-matching PRs for security notes.
      - [ ] Model changelog shows trigger-driven incremental updates (not one big-
            bang revision years ago); covered-SHA or date range recorded.
      - [ ] Incidents/pentest findings traceable into threat rows + regression
            tests.
      - [ ] Risk register ≤ 1 page, current owners, no expired review dates.
      
    • 06-audit-reconstruction.md 12.3 KB
      # 06 — AUDIT Mode: Reconstructing a Threat Model from an Existing System
      
      Goal: given a codebase (plus IaC, configs, pipelines), rebuild the threat
      model the system IMPLIES, compare it with whatever the team INTENDED, and
      report the gaps as severity-rated, evidence-backed findings. This is gap
      analysis against catalogs — not pentesting (you prove absence of controls,
      not presence of exploits) and not code review (you work at the
      boundary/control level, not line-by-line).
      
      ## 1. Audit procedure (ordered; timebox each phase)
      
      1. **Collect artifacts (30 min):** repo(s), lockfiles, IaC, CI configs,
         Dockerfiles/k8s manifests, any existing threat model/architecture docs,
         `.env.example`, OpenAPI/proto specs. Note what you were NOT given —
         un-auditable surface goes in the report as such, never silently skipped.
      2. **Extract the system model** per `02` §B: entry-point sweep, store/asset
         inventory, actor/privilege table, inferred trust boundaries. Output the
         reconstructed mermaid DFD — this diagram is deliverable #1 even if you find
         nothing else; most teams have never seen their real attack surface drawn.
      3. **Reconstruct intent:** read existing docs/ADRs/old models, auth middleware
         comments, IaC structure. Write down the implied assumptions ("services
         trust the gateway's headers", "bucket is private"). Each assumption becomes
         a test target.
      4. **Run the catalogs (`03`)** against each component → control-presence
         matrix (§2 below). Prioritize components on paths to top-3 assets when
         time-boxed; record de-scoping explicitly.
      5. **Test assumptions from step 3:** for each, find the code/config that makes
         it true. No evidence = broken assumption = finding (these are usually the
         Criticals: "gateway-only trust" with services bound to 0.0.0.0).
      6. **Gap analysis (§3):** absent/partial controls → threat sentences → rate in
         deployment context (`04` §3) → findings (§6).
      7. **Deliver (§7):** findings report + reconstructed model + remediation
         ordering. Hand the reconstructed model to the team as their new baseline
         (`05` §4) — the audit's lasting value.
      
      ## 2. Control-presence matrix
      
      For every (component × applicable catalog item) record one of:
      
      | State | Meaning | Evidence required |
      |---|---|---|
      | **Present** | Control implemented and reachable on all relevant paths | file:line of the control + how you confirmed coverage |
      | **Partial** | Implemented but bypassable, inconsistent, or covering some paths | both: where it works and where it doesn't |
      | **Absent** | No control found after a genuine search | the searches performed (so reviewers can re-run them) |
      | **N/A** | Catalog item doesn't apply | one-line reason |
      | **Unverifiable** | Outside provided artifacts | what artifact would settle it |
      
      Rules:
      - **Evidence or it didn't happen — in both directions.** "Present" without
        file:line is as worthless as "Absent" without the search trail. Audits get
        challenged; the matrix is your defense.
      - **Partial is the most important state.** One authz-checked endpoint proves
        the team knows the pattern; the seventeen unchecked ones are the finding.
        Inconsistency also tells you remediation is adoption, not invention.
      - **Sample honestly:** for repetitive surfaces (50 routes), sample ≥20% plus
        ALL routes touching top assets; state the sampling rule in the report.
      - **Check the negative space:** middleware exclusion lists, `// TODO: auth`,
        `@SkipAuth`-style decorators, IaC `count = 0`/commented blocks, disabled
        tests with `security` in the name, `.allowlist` files. Disabled controls are
        stronger findings than never-built ones (someone decided).
      
      Matrix excerpt (orders-api × API catalog, `03` §2):
      
      | Catalog item | State | Evidence |
      |---|---|---|
      | Object-level authz | **Partial** | tenant check in invoice_repo.py:22, payments.py:31; ABSENT in order_repo.py:18 + 8 of 11 sampled by-id routes |
      | Mass assignment | Present | DTO allowlists via schemas/*.py; no `**request.json` hits |
      | SSRF controls | **Absent** | webhook "test" fetch at hooks.py:77, no allowlist; searches: `requests.get(`, `urlopen`, `httpx` |
      | Rate limiting | **Unverifiable** | nginx config not provided; app-level none found |
      | Deserialization | N/A | JSON only; no pickle/yaml.load hits |
      
      ## 3. Gap analysis — from absent control to ranked finding
      
      For each Absent/Partial cell:
      
      1. **Write the threat sentence** the missing control would have addressed
         (actor → action → asset → impact), using the actual actors and assets from
         the reconstructed model — never "an attacker could potentially".
      2. **Walk the real path:** can the named actor actually reach the weakness
         from an entry point in THIS deployment? An unparameterized query fed only
         by a config constant is hygiene (Low), not injection (Critical).
         Reachability is what separates an audit from a scanner run.
      3. **Classify the gap:**
         - **Missing primary control** — nothing stands between actor and asset
           (no authz check on a reachable endpoint). Rates on raw L×I.
         - **Missing defense-in-depth** — primary control exists; backstop absent
           (authz present, but no RLS / no audit log). Cap at one band below what
           primary-control failure would rate, and say which primary it backstops.
         - **Posture/hygiene** — weakens future changes rather than today's paths
           (shared DB superuser in a single-service system). Usually Low/Medium with
           a "rises to X when Y" note.
      4. **Chain before rating.** Individually-Medium gaps that compose into a
         Critical path get ONE chained finding rated for the chain (SSRF [M] +
         IMDSv1 [M] + over-privileged role [M] = metadata-credential takeover [C]),
         with member gaps listed as remediation points. Report the chain, not three
         medium tickets nobody connects.
      
      ## 4. Severity calibration (audit-specific)
      
      Apply `SKILL.md` conventions + `04` §3 anchors, with these audit rules:
      
      - **Rate what IS, not what might be coded later.** Severity reflects current
        deployment context; include a "context sensitivity" note when one config
        change would jump the rating ("Medium today; Critical if this service is
        ever exposed publicly — see T-7").
      - **Unverifiable ≠ Low.** A control you couldn't verify on a Critical path is
        reported as "Unverified, potential High" with the artifact request —
        downgrading for lack of access rewards opacity.
      - **Broken stated assumptions inherit the severity of what relied on them.**
        If "internal network is trusted" underpins all service authn and is false,
        that single finding is Critical even though each individual service merely
        "lacks mTLS".
      - **No severity inflation for volume.** Forty Low hygiene findings do not sum
        to a High; instead emit one thematic finding ("input validation is not
        systematic: 40 instances, list attached") so the remediation is a pattern
        fix, not whack-a-mole.
      
      ## 5. Tooling and timeboxing
      
      Tools feed the audit; they are never the audit:
      
      - **Use scanners as input, not output.** SAST/dep-scan/IaC-scan results are
        candidate Absent/Partial cells — each still needs the reachability walk
        (§3.2) before it becomes a finding. Forwarding scanner output as an audit
        is the canonical failure mode of this discipline.
      - **Targeted code sweeps** (opengrep/grep) excel at the matrix's repetitive
        cells: authz-check presence per route, raw-SQL escape hatches, `verify=False`,
        skip-auth decorators, `dangerouslySetInnerHTML`. Save the rule set — it
        becomes the structural regression guard you recommend (`04` §5 VER-2).
      - **Read IaC before code.** Network policy, IAM, and bucket policy answer
        reachability questions that would take hours to establish from app code.
      
      Timebox tiers (state which tier the report represents):
      
      | Tier | Budget | Scope |
      |---|---|---|
      | Rapid | 1 day | DFD + entry-point sweep + assumptions test + top-asset paths only; catalogs for the 2–3 highest-risk components |
      | Standard | 3–5 days | Full matrix on all components on top-3 asset paths; sampled elsewhere |
      | Deep | 2+ weeks | Full matrix everywhere + chain construction + process meta-audit |
      
      A Rapid audit that says so is honest; a Rapid audit formatted like a Deep one
      is malpractice — the un-examined surface must be listed (§1.1).
      
      ## 6. Finding format (binding)
      
      Every finding uses the `SKILL.md` format. Worked example:
      
      ```
      [HIGH] Cross-tenant order read via unscoped lookup (orders-api, STRIDE-E/I)
      Location: services/orders/handlers/get_order.py:41; absent tenant filter in
                repositories/order_repo.py:18
      Threat: Any authenticated customer can read any other tenant's orders
              (PII: names, addresses — asset A1) by iterating sequential order
              IDs on GET /orders/{id}, because the lookup filters by id only and
              IDs are sequential (migrations/0042_orders.sql:7).
      Evidence: get_order.py:41 `order = repo.get(order_id)` — no tenant_id in
                query; confirmed pattern on 9 of 11 by-id endpoints sampled
                (exceptions: invoices, payments — both filter by tenant).
      Recommendation: enforce tenant scoping in the repository layer (single
                choke point, pattern already exists in invoice_repo.py:22);
                switch new IDs to UUIDv7. Map to SR-104; add abuse-case test
                per 05 §3.
      Residual risk if accepted: mass PII enumeration by any self-service
                signup; likely notifiable breach.
      ```
      
      Rules:
      - One finding = one decidable remediation. Split findings the team would
        assign to different owners; merge instances of one pattern (per §4).
      - The Evidence line must let a skeptic reproduce your conclusion from the
        repo alone. Quote minimally; cite precisely.
      - Recommendation names WHERE the control goes and reuses the team's existing
        good patterns when they exist (adoption beats invention, §2).
      - Positive observations (Present controls on critical paths) get a short
        section — they calibrate trust in the audit and stop teams "fixing" what
        works.
      
      ## 7. Audit report structure
      
      ```
      1. Scope & method: artifacts received/withheld, sampling rules, timebox,
         catalogs applied, un-audited surface.
      2. Reconstructed system model: DFD + entry-point/asset/actor tables (02).
      3. Findings: Critical → Low, chained findings first within band.
      4. Thematic observations: systemic patterns (one per theme) + positives.
      5. Control-presence matrix: appendix, full table with evidence.
      6. Assumption test results: stated/implied assumptions, held or broken.
      7. Proposed baseline: the model handed back for living maintenance (05 §4),
         pinned to the audited git SHA.
      8. Remediation ordering: chains broken at cheapest link first; pattern
         fixes over instance fixes; quick wins (config-level Criticals) flagged.
      ```
      
      Meta-findings — the audit also rates the team's PROCESS:
      - No threat model existed → Medium process finding (plus the baseline you
        deliver remediates it).
      - Model existed but drifted (trigger-matching changes since last revision,
        `05` §4) → finding, with the missed triggers listed.
      - Expired risk acceptances, orphaned threats without dispositions, abuse-case
        tests deleted/skipped → findings per `04`/`05` checklists.
      
      ## Audit checklist (meta — quality bar for the audit itself)
      
      - [ ] Artifact inventory recorded, including what was NOT provided; nothing
            silently skipped — unverifiable surface reported as such.
      - [ ] Reconstructed DFD + entry-point sweep completed per 02 §B before any
            catalog work; sweep commands/searches reproducible.
      - [ ] Implied assumptions written down and each tested against code/config;
            broken assumptions rated by what relied on them.
      - [ ] Control-presence matrix complete for in-scope components; every cell
            Present/Partial/Absent/N-A/Unverifiable with evidence or search trail.
      - [ ] Sampling rules stated; all top-asset paths examined, not sampled.
      - [ ] Negative space checked: exclusion lists, skip-auth decorators, disabled
            tests, commented-out IaC.
      - [ ] Reachability walked for every finding; hygiene vs. primary-control vs.
            defense-in-depth gaps distinguished and rated accordingly.
      - [ ] Exploit chains assembled and rated as chains; no severity-by-volume.
      - [ ] Every finding in the binding format with file:line evidence and a
            located, pattern-reusing recommendation.
      - [ ] Positive controls acknowledged; process meta-findings (stale model,
            expired acceptances) included.
      - [ ] Baseline model delivered, pinned to the audited SHA, ready for living
            maintenance per 05.
      
  • SKILL.md 9.1 KB
    ---
    name: sota-threat-modeling
    description: >-
      State-of-the-art threat modeling for both designing new systems and auditing
      existing ones. Use when designing a feature, service, integration, or
      architecture that touches untrusted input, new trust boundaries, sensitive
      data, or third-party dependencies (BUILD mode), and when reviewing, auditing,
      or pen-test-scoping an existing codebase to reconstruct its implicit threat
      model and find gaps (AUDIT mode). Not for code-level vulnerability review —
      use sota-code-security. Trigger keywords: threat model, STRIDE,
      LINDDUN, PASTA, attack tree, kill chain, data flow diagram, DFD, trust
      boundary, attack surface, abuse case, security design review, security
      architecture review, risk rating, DREAD, CVSS, security requirements,
      secure design, security audit, gap analysis, prompt injection, excessive
      agency, threat catalog, mitigations, residual risk.
    ---
    
    # SOTA Threat Modeling
    
    ## Purpose
    
    Threat modeling answers Shostack's four questions with engineering rigor:
    1. **What are we working on?** (decompose: DFD, trust boundaries, assets, actors)
    2. **What can go wrong?** (enumerate: STRIDE/LINDDUN per element, catalogs, attack trees)
    3. **What are we going to do about it?** (treat: mitigate/accept/transfer/avoid, map to requirements and tests)
    4. **Did we do a good job?** (verify: abuse-case tests, residual risk review, re-model triggers)
    
    This skill operationalizes those questions in two modes. Never produce a threat
    model that is only prose — every threat must land as a tracked requirement, a
    test, or an explicitly accepted risk with an owner.
    
    ## BUILD Mode — Threat-Model-While-Designing
    
    Run this workflow whenever designing anything that crosses a trust boundary.
    Scale effort to risk: a 15-minute "four questions" pass for a small feature; a
    full STRIDE-per-interaction model for a new service or auth flow.
    
    ### Workflow
    
    1. **Scope the delta.** Model what is new or changed, not the whole system.
       List new entry points, new data classes, new dependencies, new actors.
    2. **Draw the DFD as text/mermaid** (see `rules/02`). Mark trust boundaries
       explicitly. If you cannot draw a boundary, you do not understand the design
       yet — stop and ask.
    3. **Pick the methodology** (see `rules/01`): STRIDE-per-interaction by
       default; add LINDDUN if personal data flows; attack trees for a single
       high-value asset; four-questions-only for low-risk deltas.
    4. **Enumerate threats** crossing each boundary using the per-component
       catalogs in `rules/03`. Write each threat as: *actor → action → asset →
       impact*. No vague entries ("hacking", "data breach").
    5. **Rate and treat** each threat (see `rules/04`): likelihood × impact matrix,
       then accept / mitigate / transfer / avoid. Every mitigation becomes a
       security requirement with an ID.
    6. **Emit artifacts** (see `rules/05`): threat model doc, security requirements
       backlog entries, abuse cases as test stubs, and re-modeling triggers.
    7. **Wire into delivery.** Reference requirement IDs in the design doc, tickets,
       and PR descriptions. A threat without a tracked artifact does not exist.
    
    ### Continuous / incremental (agile, PR reviews)
    
    - Threat model the **story**, not the sprint. Add a "Security notes" section to
      design docs and PR descriptions for any change matching a re-model trigger:
      new dependency, new endpoint/route/queue/cron/webhook, new trust boundary,
      new data class, auth/authz change, file/deserialization handling.
    - In PR review, run a micro-STRIDE on the diff only: what new input enters?
      whose privilege executes it? what does it write or call? Takes 5 minutes;
      catches the majority of design-level regressions.
    
    ## AUDIT Mode — Reconstructing a Threat Model from Code
    
    Use when handed an existing system with no (trustworthy) threat model. Goal:
    rebuild the implicit model from artifacts, then diff intended vs. actual
    controls. Full procedure in `rules/06`.
    
    ### Workflow
    
    1. **Inventory entry points from code** (see `rules/02` §extraction): routes,
       queue consumers, cron jobs, webhooks, third-party callbacks, CLI/admin
       tools, file uploads, IaC-exposed ports.
    2. **Reconstruct the DFD** from the inventory: processes, stores, external
       entities, flows; infer trust boundaries from network topology, authn
       checkpoints, and IAM policies.
    3. **Identify assets and actors** from schemas, secrets handling, and config.
    4. **Run the catalogs** (`rules/03`) against each component; for every catalog
       item record: control present / absent / partial, with file:line evidence.
    5. **Gap analysis**: rank absent/partial controls by exploitability ×
       blast radius; distinguish "missing control" from "missing defense-in-depth".
    6. **Report findings** in the standard format below.
    
    ### Severity conventions
    
    | Severity | Definition |
    |---|---|
    | Critical | Remotely exploitable now, by an unauthenticated or low-priv actor, leading to full compromise of a key asset (RCE, auth bypass, mass data exfil). Fix before anything else ships. |
    | High | Exploitable with realistic preconditions (one valid account, one misconfig, MitM position) compromising a key asset; or a Critical with a single weak mitigating layer. Fix this sprint. |
    | Medium | Requires chaining, elevated access, or unusual conditions; or impacts a secondary asset; or defense-in-depth gap on a Critical path. Schedule. |
    | Low | Hardening, hygiene, info disclosure of low-value data, theoretical with strong existing controls. Backlog. |
    
    Severity = exploitability × impact in **this** deployment context — never copy
    a CVE/CVSS base score without environmental adjustment (see `rules/04`).
    
    ### Finding format (every finding, no exceptions)
    
    ```
    [SEV] TITLE (component, STRIDE/LINDDUN class)
    Location: path/to/file.py:123 (and IaC/config refs)
    Threat: <actor> can <action> via <vector> because <missing/weak control>,
            impacting <asset> (<C/I/A/privacy impact>).
    Evidence: code excerpt or config line proving the gap.
    Recommendation: specific control + where it goes; map to requirement ID.
    Residual risk if accepted: one sentence.
    ```
    
    ## Rules Index
    
    | File | Read this when... |
    |---|---|
    | `rules/01-methodologies.md` | Choosing between STRIDE, LINDDUN, PASTA, attack trees, kill chains; deciding lightweight vs. heavyweight; setting up continuous/PR-level threat modeling. |
    | `rules/02-decomposition.md` | Drawing DFDs in mermaid, defining trust boundaries, listing entry points/assets/actors/privilege levels; extracting all of these from an existing codebase. |
    | `rules/03-threat-catalogs.md` | Enumerating threats for a specific component: web frontend, API, database, message queue, file storage, CI/CD, mobile, LLM agent/tool-use, cloud/IAM. |
    | `rules/04-risk-rating-treatment.md` | Rating threats (DREAD pitfalls, CVSS usage, L×I matrices), choosing accept/mitigate/transfer/avoid, mapping mitigations to requirements and tests, documenting residual risk. |
    | `rules/05-outputs-operationalization.md` | Writing the threat model document, building the security requirements backlog, turning abuse cases into tests, keeping the model alive (re-model triggers). |
    | `rules/06-audit-reconstruction.md` | Auditing an existing system: reconstructing the model from code, control-presence matrix, gap analysis, severity calibration, reporting. |
    
    Load only the files you need; `rules/02` + `rules/03` cover 80% of day-to-day work.
    
    ## Top-10 Non-Negotiables
    
    1. **No model without a diagram.** Every threat model includes a DFD (mermaid
       or ASCII) with explicit trust boundaries. Prose-only models hide boundary
       confusion.
    2. **Threats are sentences, not nouns.** *Actor → action → asset → impact.*
       "SQL injection" is a vector; "anonymous user exfiltrates the orders table
       via unparameterized search query" is a threat.
    3. **Every entry point gets enumerated** — including queues, cron, webhooks,
       callbacks, admin tooling, and CI/CD. HTTP routes are never the whole attack
       surface.
    4. **Trust boundary crossings drive enumeration.** Apply STRIDE per
       interaction at each crossing; data inside one boundary at one privilege
       level rarely needs the full treatment.
    5. **Personal data ⇒ LINDDUN pass.** STRIDE does not cover linkability,
       identifiability, or non-compliance; run a privacy pass whenever PII flows
       or is stored.
    6. **Rate with likelihood × impact in context.** Never ship raw DREAD scores
       or unadjusted CVSS base scores as priorities.
    7. **Every threat gets a disposition.** Mitigate (→ requirement ID + test),
       accept (→ named owner + expiry date), transfer, or avoid. "Noted" is not a
       disposition.
    8. **Mitigations become tests.** Each mitigated threat yields at least one
       abuse-case test (unit, integration, or rule-based check) that fails if the
       control regresses.
    9. **LLM/agent components are first-class attack surface.** Model prompt
       injection, tool-call abuse, excessive agency, and data exfil via outputs
       for any system invoking an LLM with tools or retrieved content.
    10. **Models expire.** Define re-model triggers (new dependency, new trust
        boundary, new data class, auth change) in the document itself; an undated,
        trigger-less threat model is treated as absent in audits.
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related