Table of Contents generated with DocToc
The three security-model-* skills cover one lifecycle: getting a project's security model written, findable, and current. This page is the rationale behind them — the decisions that are the same for every adopter, kept in one place so the skills do not each re-argue them.
| Stage | Skill | Question it answers |
|---|---|---|
| Produce | security-model-prepare | The project has no written model. What does one say, and how does it land without burning maintainer goodwill? |
| Verify | security-model-verify | Can an agent find the model, and does it say enough to route a finding? |
| Update | security-model-update | Six months of triage decisions have happened. What does the model now say that it did not? |
A security model is the implicit contract between a project and its downstream users: the assumptions it makes about its environment, callers, and inputs; the properties it upholds; the properties it explicitly does not; and the misuses that are syntactically possible but outside the intended use.
It has two readers, and they need different things from the same document:
The second reader is why this matters more every year. Automated analysis produces findings at a rate no maintainer can absorb by hand, and the only thing that makes that volume survivable is a document the triage step can consult before a human does. A project without one does not get fewer findings; it gets the same findings with nobody able to close them cheaply.
The specification of what a model contains is maintained publicly by Alpha-Omega:
That repository ships an orchestrator plus specialists — recon, surface, interview, authoring, backtest, sidecar, triage — with the section structure (§1.1–§1.19), the provenance tag set, and the closed disposition set with its precedence order in skills/threat-model/references/.
Magpie references it by URL and does not vendor, mirror, or fork it. Two reasons:
What Magpie owns is everything around the rubric: the consent conversation, the discoverability chain, the PR mechanics, the confidentiality scrubbing, and the feedback loop from triage history back into the document. Those are governance and workflow concerns, which is Magpie's half of the problem.
The skills therefore cite section numbers (§1.15 known non-findings, §1.17 dispositions) as coordinates into the upstream document. When upstream renumbers, the fix is to update the citing tables — not to start keeping a local copy.
An agent finds a project's model by following a fixed chain:
AGENTS.md -> SECURITY.md -> <the model>
Any of four terminations is fine: the model embedded in SECURITY.md, an in-repo file, a project-site URL, or an umbrella model in another repository (the normal shape for build tooling, language ports, and other satellites).
This is the only check that is allowed to block. The reasoning is narrow: a model an agent cannot reach is not a worse model, it is an absent one — the scanner has to treat every component as in scope and every property as unclaimed, and the output is the hundred-finding review the model existed to prevent. Completeness, by contrast, is graded: gaps are proposals the maintainer decides on. Nothing in the completeness rubric is a precondition for anything.
The chain is also cheap to fix, which is why it gets a PR rather than a conversation. Adding one section to AGENTS.md needs no maintainer input, and the diff is small enough to review in the time it takes to read the title.
Everything substantive — model gaps, missing sections, a broken link the project owns — goes to the project's private security list, never to a public tracker. Three independent reasons, any one of which would be sufficient:
PRs are the deliberate exception. They need a repository write anyway, the diff is the artefact being ratified, and “add one link line” carries no inventory worth withholding.
PR titles, PR bodies, commit messages, and branch names on a target repository are public forever. Two rules apply to all of them:
#NNN reference is a stable identifier and is public-safe; the page behind it stays access-gated. Its contents — issue bodies, comment text, team debate, labels, assignees — are not. See the confidentiality rules in AGENTS.md.This bites hardest in security-model-update, whose entire input is private tracker material and whose entire output is a public document. Its scrub step is not a formality.
A blank-page request — “could you write up your threat model?” — is an unbounded ask, and it is why most of these efforts produce nothing. A tagged draft is a bounded one: the maintainer reads claims someone else wrote and says yes, no, or not quite per line. Reacting is far cheaper than composing, and the corrections are where the real model surfaces.
That inverts the usual risk, though. A draft written by someone who is not the maintainer, in the maintainer‘s voice, is a document that can quietly launder a guess into the project’s official position. The provenance tags are what prevent it:
| Tag | Means | Licenses closing a report? |
|---|---|---|
| documented | Lifted from a project artefact, cited | Yes |
| maintainer | Stated by a maintainer, dated | Yes |
| assumption | A working premise with an open question | Only under a declared relaxed policy, low blast radius, never security-critical |
| inferred | The drafter's guess, with an open question | No — it escalates, never closes |
No hedge variants. Every assumption and inferred claim resolves to a numbered open question. A first draft with no inferred tags is overclaiming.
It appears in the backtest, in the update loop's regression check, and in the rules for what may become a known non-finding. It is one sentence:
Wrongly escalating a non-finding wastes a maintainer's afternoon. Wrongly closing a real vulnerability hands a reporter “not a bug” on a live issue.
So: when the evidence is ambiguous, prefer the wording that leaves reports escalating. Narrow a claim to resolve a conflict; never widen one. A model that closes an item the project historically fixed does not ship — that is the single blocking outcome in both the initial backtest and every later update.
Disclaiming is the cheapest way to make an awkward routing disappear, which makes it the easiest way to pass a quality gate while making the model worse. A disclaimer added because an item routed badly is reverse-engineered from the answer; it still has to be true of the project as it is, cite a real source, and stay inside the scope that source covers.
Known non-findings (§1.15) are the recurring-false-positive list, and the section an automated triager is fed verbatim as a negative prompt. They are also first in the disposition precedence order, which means an entry there pre-empts every scope, configuration, dependency, adversary, and property check below it.
A loose entry therefore does not mis-classify one report — it suppresses a class of them, ahead of every other safeguard the model has. Hence the fence:
BY-DESIGN: property-disclaimed close, and an already-established known non-finding recurring again.OUT-OF-MODEL:* is ever promoted. Those routes sit below §1.15 in the precedence order; relabelling one lifts it above the checks that decided it, and the class widens without anyone deciding to widen it.The other half of the update loop is the gap list, and the uncomfortable entries are the valuable ones. A model that routes an item the opposite way to how the team actually resolved it, or a rejection a reporter successfully argued the team out of, is the model failing in the expensive direction under real conditions with an independent reviewer. Two reversals against the same claim mean that claim is wrong.
A canned response in <project-config>/canned-responses.md that cites no model section is a gap by definition — the project is stating a position in reporter mail that its own model does not hold. That is precisely what the drafting rule in <project-config>/security-model.md warns about, and this loop is what closes it.
The three skills read <project-config>/security-model.md: the authoritative model URL, the repositories in scope and their shape (in-repo model or pointer to an umbrella), the private list to route substantive conversation to, and the branch and license-header conventions the PR helper needs. Everything else comes from project.md.
README.md — the security skill family index.process.md — the report-handling lifecycle whose dispositions feed the update loop.confidentiality.md — what may cross to a public surface.poc-handling-policy.md — what an agent may do with reporter-supplied proof-of-concept code encountered while mining the corpus.