v1.4.0: corpus 80 to 100, AI-fingerprint detectors, mcp 2.x support
v1.4.0: corpus 80 to 100, AI-fingerprint detectors, mcp 2.x support
Twenty new rules, a class of detector the corpus did not have before, and an
SDK break fixed properly rather than pinned around. The plugin version has read
1.4.0 since this work landed; this tag makes the published release match it.
Added
-
Corpus 80 → 100 rules, in three groups.
Four AI-fingerprint detectors on the
code_reviewlogsource —ai_prose,
unicode_watermark,ai_provenance,hallucinated_import— taking that
logsource from 5 rules to 9. They sit outside the ATT&CK tactic taxonomy on
purpose: they match authorship artifacts in source, not adversary technique,
which is whycode_reviewis a rule directory but never counted as a tactic.Six observed campaigns, each bound to a named, dated incident:
- UNC1069/WAVESHAPER
axiosnpm compromise - TanStack Pwn Request Actions cache poisoning
- SharePoint CVE-2026-58644
w3wpshell spawn - N-able N-central CVE-2026-18577
cloudflaredpersistence - Storm-2949 Azure management-plane credential harvest
keyv/cacheablenpm worm ETH C2
Ten canonical templates: T1082, T1083, T1189, T1195.002, T1204, T1485,
T1546, T1552.004, T1567.001, T1574.Nothing was invented to reach a round number. The corpus stopped at 94 when
cross-verifiable material ran out, and three further candidates were rejected
for single-source or self-contradictory IOCs. T1071.001 was checked and
skipped — its frequency in the source corpus is 0. - UNC1069/WAVESHAPER
-
OpenSearch as a fifth conversion target. Lucene and PPL are separate
targets, and a test asserts they do not silently resolve to the same one. -
Processing pipelines are applied by
convert_rulerather than ignored. An
unknown pipeline name is an error; a missing pipeline package names itself in
the returned envelope instead of raising a bare traceback. -
One new rule for each of the four thinnest ATT&CK tactics, the two correlation
types the templates had not yet used, and a previously-withheld
privilege-escalation rule. -
discoverybecomes the thirteenth ATT&CK tactic covered by the corpus, up
from twelve. The heaviest growth was elsewhere:initial_access17 → 21 and
command_and_control3 → 6. -
Coverage measurement is gated on again, and the Docker image is built and
smoke-tested by speaking MCP to the container over stdio rather than assuming
it starts.
Fixed
-
write_rule_yamldate-regression guard. Found via a real near-miss:
running the corpus migration overwrote an already-deployed, fresher rule
with content re-rendered from a stale test fixture, silently backdating it.
The guard refuses any write that would backdate a deployed rule. A blocked
write means the source needs refreshing, not that the guard should be
bypassed. -
mcp2.0.0 support, properly this time. 1.3.0 responded to the SDK 2.0
break by pinningmcp<2.server.pynow importsmcp.server.MCPServeron
2.x and falls back tomcp.server.fastmcp.FastMCPon 1.x, so both majors
work and CI runs the suite against both instead of excluding one. -
The Docker image shipped without the rule corpus baked in, so both MCP
resources that readresources/examples/answeredok: falseinside the
container even though the same server worked outside it. -
Placeholder
falsepositives:entries (REPLACE_MEand similar) are gone
from the corpus, andvalidate_ruleflags any that reappear.
Verification
pytest -qin CI across six matrix jobs (ubuntu / macos / windows ×mcp<2
andmcp>=2): 419 passed in every one (332 passed, 7 skipped at v1.3.0)- Coverage 92% against the 85% floor in
.coveragerc readme_stamp.py --checkin sync:sigma_rule_count=100,
test_module_count=16- Rule
status:breakdown: 8test, 92experimental, 0stable— read
rule status before
deploying any of these - CodeQL (actions and python), bandit, ruff, dependency-licenses and the Docker
stdio smoke test all clean
Note
The [1.3.0] changelog section understated its own release: it claimed a
corpus of 76 while the tag it names ships 80. The section written for this
release then continued that 76 instead of measuring, so the two agreed with
each other and disagreed with the repository — which is why both survived
review. Both are corrected here, and CHANGELOG.md now carries the guard
README.md already had: a test asserts the newest section's rule count against
the actual corpus, and that each section starts where the previous one ended.
The GitHub release title for v1.3.0 was correct throughout; only the changelog
was wrong.