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
7.2 KiB
Security policy
This repository ships no runnable code — no package, no build, no dependency tree, nothing that executes on your machine. So the usual question, can this be exploited, has an unusual answer here: the attack surface is the data.
Seven data files here carry the detection material — pattern tables, code-point carriers, calibration thresholds, an OWASP mapping — and several independent runtimes read them at the same time. A wrong code point, a mis-escaped regex, a fixture that expects a miss: none of that crashes anything. It produces a detector that looks like it works and is not looking. That is the vulnerability class this policy is about, and a report of one is welcome even though no code changes as a result.
Reporting
Do not open a public issue. A report here usually names an input that gets past a detector, and that is a working bypass against every consumer until it is closed.
Report privately by email:
- hello@fromaitochitta.com, with
SECURITYat the start of the subject.
Pull requests are not the channel either — they are switched off on the canonical repository, and not as an oversight. This repository is vendored into independent runtimes that pin a tag; a change to detection data changes what those runtimes find. Such a change has to be coordinated with each consumer before it exists, which a merge button does not do. Fork-and-own is the supported path.
Please include:
- the file and the entry — its
name,orderorid, whichever that file uses; - the tag you read (
v0.3.0, not "main"); - the input that should have matched and does not, or the input that matches and should not;
- what a consuming runtime actually does today, if you have measured it.
Obfuscate live payloads. Do not send a working credential or a live carrier. Spell
invisible characters as code points the way the tables do ("U+200B"), and use placeholder
key material — a report should not itself be a delivery mechanism.
What counts as a vulnerability here
In scope — all of these are real reports:
- A detection entry that is a silent false negative. A wrong code point, a regex whose escaping is wrong for the declared dialect, missing or wrong flags, a pattern that fails to compile in a documented engine and gets skipped rather than reported.
- A conformance fixture that sanctions a miss.
expected.jsonis ground truth: a runtime that disagrees with it is deemed wrong. A fixture that expects too little makes every conforming runtime wrong identically, and the corpus will not catch it. - A normative clause that mandates unsafe behaviour. The
spec/files bind the implementations that consume them, so a weak rule propagates to all of them. - A real secret or personal data in the repository or its history. The history is public in full.
- Data that has gone stale against its declared source in a way that under-detects.
Each data file names its source in a
provenanceblock. If that source has since added or corrected an entry, the copy here under-matches, and a consumer vendoring it is less protected than the runtime it was taken from.
Out of scope — documented boundaries, not vulnerabilities. See Known limitations and Non-goals in README.md:
- a detection class absent from the tables entirely (coverage is the union of what the seed implementations detected, not of what exists);
- a table implemented by only one runtime, and cases marked
not-applicablefor the others; - disagreement about a
calibration.jsonthreshold — the thresholds are published, the policy built on them belongs to the consumer; - a divergence already recorded in
docs/lexicon-port-divergence.md; - the five data files no fixture constrains, and the finite homoglyph map.
If you are unsure which side something falls on, report it privately anyway.
Why a confirmed defect is usually not fixed here first
This is the part that differs from an ordinary repository, and it is worth reading before you conclude that a fix is being stalled.
Most data here is an extraction: a copy of a table that lives in a runtime, kept behaviour-identical to it on purpose. Correcting an entry here — even a genuinely wrong one — would make the copy disagree with the implementation it was taken from. Two implementations answering differently on the same input is precisely the failure this repository exists to prevent, so producing one as a fix would be self-defeating.
A confirmed defect in extracted data therefore travels:
- the report reaches the maintainer here, privately;
- the owning runtime is identified — every data file names it in
provenance.source_repo— and the report is routed there; - the decision is taken there, where the pattern is under test against a real suite;
- once the source has moved, this repository re-extracts from a pinned public commit and tags a release;
- consumers pull that tag on their own schedule.
Stated plainly, because it affects you: fix latency is bounded by the owning runtime's schedule and by each consumer's pull, not by this repository's. If you need protection sooner than that, the fix belongs in your own runtime; this repository is where it becomes shared, not where it becomes real.
Two things do not take that route:
- A real secret in the repository or its history (class 4) is handled here, immediately.
- Data authored in this repository rather than extracted — it is flagged as such where
it occurs, for example
authored_payloadsinconformance/manifest.json— is this repository's own to correct.
The precedent is on the record. In v0.3.0 a detection pattern changed value here for the
first time, and it changed because the owning runtime had changed its own and this
repository re-read the source — not because a reviewer here judged the old value wrong.
docs/lexicon-port-divergence.md records a row where two runtimes still disagree and this
repository deliberately did not pick a winner. Provenance is the ground for moving a
value. Merit is not, and the day it becomes the ground, the guarantee is gone.
Supported versions
Pre-1.0. Only the latest tag is fixed; there are no back-ported branches.
Consumers vendor this repository (git subtree, or a pinned copy) rather than installing
it, so a fix reaches a consumer only when that consumer pulls the new tag. There is no CI in
this organisation and nothing polls for updates. When a fix changes detection data, the
maintainer notifies the known consumers directly — but their upgrade is their own action, on
their own schedule.
Read the CHANGELOG.md entry before upgrading rather than the version number: in 0.x, a
change to what a conforming runtime finds is still a minor bump.
Disclosure
There is no formal embargo SLA here. The maintainer will acknowledge the report, agree a fix
and disclosure timeline with the reporter, and credit the reporter in the CHANGELOG.md
entry unless they prefer to remain anonymous.
If the report is a false negative in a table that has already shipped, the changelog entry will say what slipped through, in enough detail that a consumer still pinned to the older tag can judge whether it is exposed. Naming it is the point of fixing it.