Skip to content

docs(readme): document the nine undocumented catalogue rules and reconcile the counts - #133

Merged
rodrigorjsf merged 3 commits into
mainfrom
docs/readme-rule-catalogue
Aug 22, 2026
Merged

rodrigorjsf merged 3 commits into
mainfrom
docs/readme-rule-catalogue

Conversation

@rodrigorjsf

Copy link
Copy Markdown
Owner

Closes #131.

Nine catalogue rules had no row in README.md's Vulnerability Patterns tables and two whole
security categories had no section at all. The 2.9.6 upstream sync reconciled the headline counts
to mean the number of rows the tables carry, which made the gap not merely incomplete but false:
the page asserted a number a reader could check on the page, and the check failed.

What lands

  • Nine rows added — AS1, AS2, AS3 (new Agent Snooping section), SSRF1, SSRF2,
    SSRF3 (new Server-Side Request Forgery section), E5 under Data Exfiltration, SC7 under
    Supply Chain, TM4 under Tool Misuse.
  • Every count reconciled — the Features bullet and the Vulnerability Patterns lead-in move from
    86 patterns across 20 categories to 95 across 22; the Specification Conformance lead-in moves
    from 77 to 95; the ### Data Exfiltration, ### Supply Chain and ### Tool Misuse headings
    move to (5 patterns), (9 patterns) and (4 patterns).
  • Two rows corrected on review — AS1 matches .continue/ as well as the three directories its
    row named, and SSRF2's patterns cover loopback and the private ranges but no link-local
    range
    ; the row had inherited that claim from the module's own comment, which is a separate
    (unfixed, out-of-scope-here) inaccuracy in static_patterns_ssrf.py's comment.
  • A note beside the inherited-documentation marker recording that the pattern counts and the
    per-category ### headings below it are the fork's reconciliation, so the next syncer resolving a
    conflict there keeps the fork's side instead of rediscovering why.

### Supply Chain (9+ patterns) became (9 patterns), deliberately

The + stood for a row the table did not list. With SC7 added, the table carries all nine Supply
Chain rules the catalogue declares, and a heading's number is defined as the count of rows in its
own table. SC4's live OSV.dev lookup makes the number of findings unbounded — not the number of
rules — so the + was measuring the wrong thing.

The OWASP crosswalk acceptance criterion is discharged elsewhere

The brief asked for docs/OWASP-AST10-COVERAGE.md to be updated with the nine rules, and that work
was built and then dropped from this PR. The maintainer has since ruled that this fork does not
carry a document upstream has withdrawn: upstream owns the truth about the core, and the fork adapts
its rules for the frameworks it implements. docs/OWASP-AST10-COVERAGE.md is upstream text upstream
deleted in c54967a, so it is retired rather than extended — that is #111, and it ships as its own
pull request immediately after this one. Crosswalking nine upstream rules into a page about to be
removed would have been work with a negative lifespan.

Below the marker

The rule tables, the pattern counts and the category headings all live below the
# Inherited documentation marker, so this change necessarily edits below it. Nine rows and two
### sections are pure insertions; six count strings are rewritten in place. No upstream row,
paragraph or URL is deleted. The deviation predates this branch — git show upstream/main:README.md
reads 70 vulnerability patterns across 17 categories while main already carried 86 across 20.

Verification

Run on this branch, at c2529cc:

make test-unit      4393 passed, 14 skipped, 38 deselected, 4 xfailed
make lint           All checks passed!
make format-check   258 files already formatted
make update-snapshots + git status --short   -> clean, no churn

Follow-up filed, not fixed here

The catalogue emits six further non-SPEC rule ids that appear nowhere in README.md — PE4,
PE5, RP1, RP2, RP3 and AE1. They are outside #131's frame (its reproducer is scoped to
PATTERN_NAMES, which does not declare them) and are filed separately.

Nine rule ids the pattern catalogue declares had no row in the
Vulnerability Patterns tables: AS1-AS3, E5, SC7, SSRF1-SSRF3 and TM4.
Two of them were whole categories the page never mentioned, so a reader
gating on "is SSRF covered?" found no answer while static_patterns_ssrf
ran on every scan.

Add Agent Snooping and Server-Side Request Forgery as their own sections,
and E5, SC7 and TM4 as rows in the categories that already existed.
Severity and display name are read from the analyzer module that emits
each rule, not inferred from a neighbour.

The two new sections sit at the tail of the static-pattern block, before
Behavioral AST, in PatternCategory declaration order. That is the rule the
surrounding sections already follow: the static block is enum order with
only Anti-Refusal hoisted, and the behavioral, YARA, MCP and framework
blocks are analyzer families that come after it.

Supply Chain's "9+" is resolved to "9" rather than kept. The "+" stood for
a row the table did not list; with SC7 added the table carries all nine
Supply Chain rules the catalogue declares, and a heading's number is
defined as the count of rows in its own table. SC4's live OSV.dev lookup
makes the number of *findings* unbounded, not the number of rules.

Both headline numbers are re-derived from the tables: 86 across 20 becomes
95 across 22, in the Features bullet, the Vulnerability Patterns lead-in
and the Contributing table's "rather than among the 86". Those three are
the only places in the repository that carry the count.

Documentation only. No rule, analyzer or test changed, and no snapshot
moved.

Refs #131

Signed-off-by: Rodrigo França <rodrigo_rjsf@hotmail.com>
67d38a1 moved the pattern total from 86 across 20 to 95 across 22 in
three places, and its body claimed those three were the only places in
the repository carrying the count. That claim was wrong. Two more sites
carry it, both in this same file, and both are the trap the issue named:
a count hidden as arithmetic or as different phrasing rather than as the
headline number.

- README.md:47, the Framework support matrix. The Agent Skills row read
  "the full 77-pattern base catalog applies". The base catalog is defined
  twelve lines below as every rule the framework rows add to, so it is
  the tabled rows minus the two framework tables. On main that was
  86 - 9 = 77 and the cell was true; 67d38a1 made it 95 - 9 = 86 and left
  the cell at 77, so the diff introduced the error rather than inheriting
  it. It now states 86 with the derivation beside it, because 86 is also
  the old total and a bare 86 there would read as a number the
  reconciliation missed rather than as one it recomputed.

- README.md:1247, the Specification Conformance lead-in. "Counted apart
  from the 77 patterns above" — "the patterns above" is the whole
  Vulnerability Patterns block including both framework tables, so it
  must equal the headline. This one was already stale on main (77 against
  a headline of 86, left behind by the 2.9.6 sync) and 67d38a1 widened
  the gap to 18. It now reads 95.

Measured, not recalled. A script walking the "## Vulnerability Patterns"
section returns 95 non-conformance rows across 22 category tables, 9 of
them in the LangChain4j and Deep Agents tables, so base = 86; every
heading's own "(<n> patterns)" equals the rows in its table. The issue's
reproducer returns an empty list. Sweeping README.md, CONTEXT.md, docs/,
.claude/ and src/ for numeric rule claims, for the phrasings that hide
one ("among the", "apart from the", "base catalog"), and for a stale
category count leaves five count sites, all now agreeing: README.md:47,
:510, :554, :1003 and :1247.

Documentation only. No rule, analyzer or test changed, and no snapshot
moved.

Refs #131

Signed-off-by: Rodrigo França <rodrigo_rjsf@hotmail.com>
AS1 matches `.continue/` as well as the three directories its row named, and
SSRF2's patterns cover loopback and the private ranges but no link-local
range -- the row inherited that claim from the module's own comment.

The counts and the per-category `###` headings below the inherited-documentation
marker are the fork's reconciliation rather than upstream's text, and a syncer
resolving a conflict on one has had to rediscover that each time. Say so beside
the marker, where the conflict is read.

Signed-off-by: Rodrigo França <rodrigo_rjsf@hotmail.com>
@rodrigorjsf
rodrigorjsf merged commit 0d716af into main Aug 22, 2026
5 checks passed
@rodrigorjsf
rodrigorjsf deleted the docs/readme-rule-catalogue branch August 22, 2026 13:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Nine catalogue rules have no README row, and two whole categories are undocumented

1 participant