Threat model authoring
Skill alpha-omega-security/threat-model/skills/threat-model-authoring
Agent skill for producing threat models for open-source projects
npx -y skills add alpha-omega-security/threat-model --skill threat-model-authoringAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- 28 days oldThe repository was created 28 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
- 5 stars5 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Draft phase 3.5 of a threat model from the orientation brief, surface analysis, and maintainer answers. USE WHEN writing docs/threat-model.md to the canonical §1.1–§1.19 structure. Combines concise prose with the §1.7 trust table and contract matrix, §1.8 output statements, §1.17 disposition table, §1.1 triager quick-start, and any prior-policy back-map. Tags every non-trivial claim as documented, maintainer, or inferred; maps inferred claims to §1.18; and maintains confidence counts. DO NOT USE FOR: sidecar generation, backtesting, or triage.
SKILL.md
7.7 KB, as published. Nobody here has run it
Threat Model — Authoring (draft the document)
Phase 3.5. Write the deliverable to the section structure in output-structure.md. Read principles.md first — the style bar is "describe the project as it is, not as it should be," and "write so a human can read it": short, direct sentences (one idea each), plain words, active voice, real verbs over nominalizations, and short bulleted lists or table rows instead of piled-up noun stacks. Target the reading level of good developer documentation, not a research paper — accuracy first, but never at the cost of plain prose.
The deliverable deliberately mixes both kinds of content in one document:
- Unstructured — plain prose and short bulleted lists carrying the reasoning (scope, adversary model, properties provided / not provided, false friends, downstream responsibilities, known misuses).
- Structured — meaningful tables embedded inline: the §1.7 per-input-operand
input-trust table and contract-dimension matrix, the §1.8 output-taint
statements, the §1.17 closed disposition set, and the §1.1 boxed triager
quick-start. (The separate
machine-readable
threat-model.yamlisthreat-model-sidecar's job.)
Assemble from the upstream artifacts
- §1.2/§1.3 from the recon component-family carve and out-of-scope inventory.
- §1.4/§1.5/§1.7/§1.8 from the surface analysis (reachability preconditions, side-effects inventory, per-input-operand table, contract-dimension matrix, output taint).
- §1.6/§1.9/§1.10/§1.11/§1.12/§1.13/§1.14/§1.15 seeded from recon's mined maintainer positions and promoted as interview answers arrive.
- §1.1 header, §1.16, §1.17, §1.18 authored here to bind the whole together.
- Prior-policy back-map appendix from recon whenever
SECURITY.mdor an equivalent authoritative model existed; retain every source claim until a maintainer explicitly approves removing the map.
Provenance discipline (non-negotiable)
- Every non-trivial claim carries exactly one of (documented, source),
(maintainer, YYYY-MM), (assumption, QN), (inferred, QN). The
QNon an assumption or inferred tag resolves to §1.18. No hedge-tags ("implicit", "documented in purpose", "generally known"). - Prefer documented disclaimers to open questions. When code + docs show a
guarantee is simply not made (no thread-safety, no resource bound, no failure
atomicity), record it as a (documented) §1.12 disclaimer — the absence is
verifiable. Reserve
unresolved/ (inferred) for dimensions where a guarantee plausibly exists but was not confirmed. This is the main lever for cuttingMODEL-GAPwithout weakening closure safety. - Assumption vs inferred. Use (assumption, QN) for a conservative default
you are willing to act on now (it may close low-blast-radius reports under the
relaxedpolicy); use (inferred, QN) when the question is genuinely open (escalate-only under every policy). Do not relabel a guess as (documented) to make it close — that launders the author's inference into the project's authority and is forbidden. - Every (inferred) and (assumption) tag has a matching §1.18 item that states a proposed answer. Mapping is one-directional: inferred/assumption → question required; extra edge-case/meta questions are allowed.
- Keep the header's draft-confidence count (documented / maintainer /
inferred, plus assumption when used) current, and declare the triage
policy (
strictdefault, orrelaxed). A draft with no (inferred) / (assumption) is fully reviewed or overclaiming; mostly unratified is not ready to publish. - Retain tags in the published version — a closed report cites (maintainer, 2025-03), and bare prose is not defensible. Footnotes are fine; keep the chain of authority intact.
Section-specific must-dos
- §1.1 — version binding, reporting cross-reference, status (incl.
unratified draftwhen §3.7 applies), triage-policy declaration (strictdefault /relaxed), provenance legend, draft-confidence count, backtest note, sibling models, and the boxed triager quick-start whose steps reference sections that actually exist. - §1.7 — a table, not prose; mark any untabled remainder from the surface timebox. Include control kinds and the per-family contract-dimension matrix. Every matrix row is claimed, disclaimed, N/A with reason, or unresolved.
- §1.7-§1.12 contract closure — promote claimed rows to §1.11 (or their owning environment/output section), disclaimed rows to §1.3/§1.12, and unresolved rows to proposed-answer §1.18 questions. No row may remain implicit.
- §1.8 — state the taint of every output channel, including the "output is as untrusted as input" one-liner where it applies; promote structural output invariants to §1.11.
- §1.11 — each property carries a violation symptom and a severity tier; resource properties state a threshold, not just a direction.
- §1.12 — at least as substantive as §1.11; call out false friends (CRC≠MAC, hash≠collision-resistant, PRNG≠CSPRNG, sandbox≠isolation) and name the well-known attack classes for this category (compression bombs, XXE, ReDoS, billion-laughs) — one sentence each.
- §1.13 — at least as substantive as §1.11; fold in every §1.6 dev-only knob and every risky §1.8 "must not assume" as a positive obligation.
- Stateful APIs — state failure postconditions where relevant, including callback/collaborator exceptions and partial mutation.
- §1.17 — the closed disposition set, each citing its licensing section,
including
dependency-contract; add the all-status closure constraint. - Closure safety — an (inferred) claim never licenses a closing
disposition, regardless of status. An (assumption) closes only what the
declared triage policy permits (
strict: never;relaxed: low-blast-radius provisional closes only), and never a security-criticalproperty-disclaimed,KNOWN-NON-FINDING, ordependency-contract. An accepted model has no inferred or assumption claims; retain review/draft status while any §1.18 item remains.
Style rules
- Plain prose and short lists. Tables only when every cell is meaningful — no templated tables with empty cells.
- When a property is not guaranteed, say so plainly ("Constant-time comparison is not provided" beats silence).
- Do not hedge into uselessness ("may or may not be safe depending on usage"). If
you cannot get a clear answer, record an
unresolvedmatrix row and a proposed-answer §1.18 question. - Cut anything that belongs in a code review/audit, restates the README, or is a
generic platitude. Every section is substantive or marked
Not applicable — <reason>.
Output
docs/threat-model.md (or the project's house path), ready for the
threat-model-backtest gate and the threat-model-sidecar derivation. Keep it
to one sitting (3–8 pages) — sprawl is a smell.