docs(security): the attack surface here is data, so the report route had to say where a wrong entry gets fixed

org-ops recorded SECURITY.md as missing against the org standard (coord,
2026-08-11) and this repository owed it for a sharper reason than "given what
the repo is about": nothing here runs, so a report is never a crash — it is a
detection entry that looks like it works and is not looking.

SECURITY.md therefore answers what an ordinary policy does not have to: how to
report that a detection-table entry is WRONG, and why a confirmed defect in
extracted data is decided in the runtime it was extracted from before it is
changed here. Correcting it here would make the copy disagree with the
implementation it was taken from — two runtimes, two answers on one input, the
exact failure this repository exists to prevent. Two classes skip that routing:
a real secret in the history, and data authored here rather than extracted.
Fix latency is stated plainly as bounded by the owning runtime's schedule and
the consumer's pull, not by ours.

secret-egress 0.1.0 -> 0.2.0 is a staleness DISCLOSURE, not a data change: all
18 patterns byte-identical, one evidence_limits entry added. llm-security
reports the source table at 19 entries now; recorded as their report and not
reproduced, because the commit carrying it is not on their public remote —
measured at b1ba1fb today. What was measured here: none of the 18 patterns
matches a legacy sk-...T3BlbkFJ... shape. A consumer vendoring this file
under-matches the seed hook by one entry, and now reads that in the file.

manifest 0.3.0 -> 0.3.1 corrects the secret-egress blocker. Through 0.3.0 it
named gcp-service-account-json and openai-api-key-legacy together as ids
"absent here". Measured against the guard at e671edb by running this file's own
18 patterns over a service-account document: a COMPLETE service-account key
file is matched here at order 11, since the PEM entry's prefix group is
optional and the bare PKCS#8 header matches; the same document with private_key
removed matches nothing here while the guard's marker still fires. That is a
cut-point difference, which is what the blocker is about, not a missing entry.
openai-api-key-legacy IS a real hole and is now recorded as one. Folded into
the existing blocker string rather than a sibling key, because blockers is a
map from table path to text.

Verified: all JSON well-formed; every non-fixture JSON has a top-level version;
charter clean (no executable code); patterns[] and count byte-identical to HEAD
for secret-egress; manifest key set unchanged and count still 90; 90 case
directories untouched; every spec still carries its normative marker.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T85QqeiWBEoBMjWaMiBnxD
This commit is contained in:
Kjell Tore Guttormsen 2026-08-11 14:03:24 +02:00
commit 0e765a02eb
5 changed files with 201 additions and 4 deletions

View file

@ -11,8 +11,64 @@ case ids, disposition semantics). Each JSON file additionally carries its own
## [Unreleased]
## [0.3.1] — 2026-08-11
**No pattern changed value. One shipped table is disclosed as stale, and the repository gains
the reporting route it did not have.** Nothing in `patterns`, `expected.json` or any id moved,
so a runtime that passes `0.3.0` passes `0.3.1` unchanged. Read the first entry anyway if you
vendor `signatures/secret-egress.json`: it now says, in the file, that it under-matches its own
source by one entry.
### Added
- `SECURITY.md` — the reporting route for a repository whose attack surface is **data**. It
answers the question an ordinary security policy does not have to: how to report that a
*detection-table entry is wrong*, and why a confirmed defect in extracted data is decided in
the runtime it was extracted from before it is changed here. Names what is in scope (a silent
false negative, a fixture that sanctions a miss, an unsafe normative clause, a secret in the
history, data gone stale against its source), what is a documented boundary rather than a
vulnerability, and the two classes that skip the routing — a real secret, and data authored
here rather than extracted. States plainly that fix latency is bounded by the owning runtime's
schedule and the consumer's pull, not by this repository's.
Written because `org-ops` recorded the file as missing against the org standard on
2026-08-11, and because four files here are detection data where a mistake is a detector that
looks like it works. `CONVENTIONS.md`, recorded in the same message, is not in this release.
- `README.md` — a short **Reporting a wrong entry** section pointing at it. Without it the
policy is a file nobody looking at the front page would know to open.
### Changed
- `signatures/secret-egress.json` `0.1.0``0.2.0` — **a staleness disclosure, not a data
change.** All 18 patterns are byte-identical to `0.1.0`; one entry is added to
`provenance.evidence_limits`. `llm-security` reports having taken the source `SECRET_PATTERNS`
from 18 to 19 by adding `OpenAI Legacy API Key`. That is recorded as their report and
explicitly **not** reproduced here — the commit carrying it is not on their public remote,
which was measured at `b1ba1fb` on 2026-08-11. What *was* measured here: none of the 18
patterns matches a legacy `sk-…T3BlbkFJ…` key shape. So a consumer vendoring this file
under-matches the seed hook by one entry, on a live credential shape, and now reads that in the
file rather than inferring it. It will be closed by re-extraction from a pinned public commit,
never by authoring the entry here from a message.
- `conformance/manifest.json` `0.3.0``0.3.1` — the `scope_planned.blockers` text for
`signatures/secret-egress.json` is corrected. Through `0.3.0` it ended by naming
`gcp-service-account-json` and `openai-api-key-legacy` together as ids "absent here". They are
two different kinds of fact, and one of them was misleading.
Measured 2026-08-11, by running this file's own 18 patterns in `order` over a service-account
document, against the guard at commit `e671edb`: a **complete** GCP service-account key file
*is* matched here, at order 11 (`Private Key PEM Block` — its `(?:RSA |EC |DSA |OPENSSH )?`
prefix group is optional, so the bare PKCS#8 header such a file carries matches). The same
document with `private_key` removed matches nothing here while the guard's marker pattern still
fires. That is a **cut-point** difference — the guard detects the document marker, this table
detects the key material — which is what the blocker is about, and not a missing entry.
`openai-api-key-legacy`, by contrast, is a real hole here today, and is now recorded as one.
The correction is folded into the existing blocker string rather than added as a sibling key:
`blockers` is a map from table path to text, and a second key under a table path would read as
a second table to anything iterating it.
- `docs/lexicon-port-divergence.md` (informative) — the residual `[^>]` vs `[^><]` row gains a
fuller witness set. `llm-security` measured the three forms as **totally ordered** by what they
match, each a strict superset of the next, and named two input classes the guard's narrower