agent-threat-rules 4.1.5 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +688 -1
- package/README.md +355 -125
- package/dist/adapters/openshell-filter.d.ts +10 -3
- package/dist/adapters/openshell-filter.d.ts.map +1 -1
- package/dist/adapters/openshell-filter.js +10 -3
- package/dist/adapters/openshell-filter.js.map +1 -1
- package/dist/adapters/stdio-adapter.js +3 -3
- package/dist/adapters/stdio-adapter.js.map +1 -1
- package/dist/cli/mcp-tools-document.d.ts +40 -0
- package/dist/cli/mcp-tools-document.d.ts.map +1 -0
- package/dist/cli/mcp-tools-document.js +95 -0
- package/dist/cli/mcp-tools-document.js.map +1 -0
- package/dist/cli/scan-handler.d.ts +8 -0
- package/dist/cli/scan-handler.d.ts.map +1 -1
- package/dist/cli/scan-handler.js +126 -34
- package/dist/cli/scan-handler.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +80 -43
- package/dist/cli.js.map +1 -1
- package/dist/converters/sarif.d.ts +14 -2
- package/dist/converters/sarif.d.ts.map +1 -1
- package/dist/converters/sarif.js +7 -9
- package/dist/converters/sarif.js.map +1 -1
- package/dist/corpus-event.d.ts +47 -5
- package/dist/corpus-event.d.ts.map +1 -1
- package/dist/corpus-event.js +68 -29
- package/dist/corpus-event.js.map +1 -1
- package/dist/embedding/model-loader.d.ts +2 -0
- package/dist/embedding/model-loader.d.ts.map +1 -1
- package/dist/embedding/model-loader.js +3 -1
- package/dist/embedding/model-loader.js.map +1 -1
- package/dist/enforcement.d.ts +8 -0
- package/dist/enforcement.d.ts.map +1 -1
- package/dist/enforcement.js +10 -0
- package/dist/enforcement.js.map +1 -1
- package/dist/engine.d.ts +150 -6
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +337 -76
- package/dist/engine.js.map +1 -1
- package/dist/eval/embedding-provenance.d.ts +40 -0
- package/dist/eval/embedding-provenance.d.ts.map +1 -0
- package/dist/eval/embedding-provenance.js +71 -0
- package/dist/eval/embedding-provenance.js.map +1 -0
- package/dist/eval/eval-harness.d.ts +34 -0
- package/dist/eval/eval-harness.d.ts.map +1 -1
- package/dist/eval/eval-harness.js +49 -2
- package/dist/eval/eval-harness.js.map +1 -1
- package/dist/eval/hackaprompt-corpus.d.ts +12 -0
- package/dist/eval/hackaprompt-corpus.d.ts.map +1 -1
- package/dist/eval/hackaprompt-corpus.js +15 -1
- package/dist/eval/hackaprompt-corpus.js.map +1 -1
- package/dist/eval/hackaprompt-provenance.d.ts +52 -0
- package/dist/eval/hackaprompt-provenance.d.ts.map +1 -0
- package/dist/eval/hackaprompt-provenance.js +108 -0
- package/dist/eval/hackaprompt-provenance.js.map +1 -0
- package/dist/eval/run-hackaprompt-benchmark.d.ts +18 -8
- package/dist/eval/run-hackaprompt-benchmark.d.ts.map +1 -1
- package/dist/eval/run-hackaprompt-benchmark.js +154 -64
- package/dist/eval/run-hackaprompt-benchmark.js.map +1 -1
- package/dist/eval/run-pint-benchmark.js +11 -1
- package/dist/eval/run-pint-benchmark.js.map +1 -1
- package/dist/eval/skill-benchmark.d.ts +26 -6
- package/dist/eval/skill-benchmark.d.ts.map +1 -1
- package/dist/eval/skill-benchmark.js +49 -16
- package/dist/eval/skill-benchmark.js.map +1 -1
- package/dist/flywheel.d.ts +4 -0
- package/dist/flywheel.d.ts.map +1 -1
- package/dist/flywheel.js +12 -4
- package/dist/flywheel.js.map +1 -1
- package/dist/hook-handler.d.ts +11 -1
- package/dist/hook-handler.d.ts.map +1 -1
- package/dist/hook-handler.js +84 -16
- package/dist/hook-handler.js.map +1 -1
- package/dist/hook-tool-output.d.ts +47 -0
- package/dist/hook-tool-output.d.ts.map +1 -0
- package/dist/hook-tool-output.js +110 -0
- package/dist/hook-tool-output.js.map +1 -0
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/layer-integration.d.ts +4 -2
- package/dist/layer-integration.d.ts.map +1 -1
- package/dist/layer-integration.js +6 -2
- package/dist/layer-integration.js.map +1 -1
- package/dist/mcp-server.d.ts +8 -0
- package/dist/mcp-server.d.ts.map +1 -1
- package/dist/mcp-server.js +1 -0
- package/dist/mcp-server.js.map +1 -1
- package/dist/mcp-tools/scan.d.ts.map +1 -1
- package/dist/mcp-tools/scan.js +9 -1
- package/dist/mcp-tools/scan.js.map +1 -1
- package/dist/measurement/enforce-lane.d.ts +66 -0
- package/dist/measurement/enforce-lane.d.ts.map +1 -0
- package/dist/measurement/enforce-lane.js +89 -0
- package/dist/measurement/enforce-lane.js.map +1 -0
- package/dist/measurement/from-eval-harness.d.ts +16 -3
- package/dist/measurement/from-eval-harness.d.ts.map +1 -1
- package/dist/measurement/from-eval-harness.js +15 -5
- package/dist/measurement/from-eval-harness.js.map +1 -1
- package/dist/measurement/in-sample-ablation.d.ts +29 -0
- package/dist/measurement/in-sample-ablation.d.ts.map +1 -0
- package/dist/measurement/in-sample-ablation.js +45 -0
- package/dist/measurement/in-sample-ablation.js.map +1 -0
- package/dist/measurement/schema.d.ts +38 -1
- package/dist/measurement/schema.d.ts.map +1 -1
- package/dist/measurement/schema.js +43 -1
- package/dist/measurement/schema.js.map +1 -1
- package/dist/quality/action-eligibility.d.ts +4 -2
- package/dist/quality/action-eligibility.d.ts.map +1 -1
- package/dist/quality/action-eligibility.js.map +1 -1
- package/dist/rule-confidence.d.ts +31 -0
- package/dist/rule-confidence.d.ts.map +1 -0
- package/dist/rule-confidence.js +49 -0
- package/dist/rule-confidence.js.map +1 -0
- package/dist/rule-scaffolder.d.ts.map +1 -1
- package/dist/rule-scaffolder.js +43 -4
- package/dist/rule-scaffolder.js.map +1 -1
- package/dist/semantic-evaluator.d.ts.map +1 -1
- package/dist/semantic-evaluator.js +15 -13
- package/dist/semantic-evaluator.js.map +1 -1
- package/dist/shadow-evaluator.d.ts +7 -2
- package/dist/shadow-evaluator.d.ts.map +1 -1
- package/dist/shadow-evaluator.js +29 -25
- package/dist/shadow-evaluator.js.map +1 -1
- package/dist/testcase-event.d.ts +82 -1
- package/dist/testcase-event.d.ts.map +1 -1
- package/dist/testcase-event.js +135 -16
- package/dist/testcase-event.js.map +1 -1
- package/dist/tier0-invariant.d.ts.map +1 -1
- package/dist/tier0-invariant.js +1 -0
- package/dist/tier0-invariant.js.map +1 -1
- package/dist/tier1-blacklist.d.ts.map +1 -1
- package/dist/tier1-blacklist.js +1 -0
- package/dist/tier1-blacklist.js.map +1 -1
- package/dist/tool-definition-scope.d.ts +45 -0
- package/dist/tool-definition-scope.d.ts.map +1 -0
- package/dist/tool-definition-scope.js +68 -0
- package/dist/tool-definition-scope.js.map +1 -0
- package/dist/types.d.ts +42 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/verdict.d.ts +46 -2
- package/dist/verdict.d.ts.map +1 -1
- package/dist/verdict.js +99 -14
- package/dist/verdict.js.map +1 -1
- package/package.json +2 -1
- package/rules/agent-manipulation/ATR-2026-00030-cross-agent-attack.yaml +2 -2
- package/rules/agent-manipulation/ATR-2026-00139-casual-authority-redirect.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00328-named-mode-persona-override.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00330-yoja-allcaps-settings-block-persona.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00418-weknora-mcp-config-rce.yaml +5 -5
- package/rules/agent-manipulation/ATR-2026-00432-superagi-output-handler-eval-rce.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00440-semantic-kernel-vector-store-eval-rce.yaml +3 -3
- package/rules/context-exfiltration/ATR-2026-00426-nl-output-injection-credential-leak.yaml +1 -1
- package/rules/context-exfiltration/ATR-2026-00702-ipi-credential-exfil-via-agent-action.yaml +1 -1
- package/rules/context-exfiltration/ATR-2026-00707-ipi-file-exfil-with-destroy-or-tamper.yaml +1 -1
- package/rules/context-exfiltration/ATR-2026-00851-indirect-pi-financial-payment-exfil.yaml +1 -1
- package/rules/context-exfiltration/ATR-2026-01457-sysprompt-completion-clone-attack.yaml +1 -1
- package/rules/context-exfiltration/ATR-2026-01462-sysprompt-override-pseudo-admin.yaml +1 -1
- package/rules/context-exfiltration/ATR-2026-01463-imend-imsystem-prompt-injection-format.yaml +1 -1
- package/rules/context-exfiltration/ATR-2026-01606-ssrf-internal-network-scan.yaml +1 -1
- package/rules/context-exfiltration/ATR-2026-02847-policy-justified-exfil-to-email.yaml +1 -1
- package/rules/context-exfiltration/ATR-2026-02855-cross-email-exfil-relay.yaml +79 -0
- package/rules/context-exfiltration/ATR-2026-02861-exfil-send-email-with-body-directive.yaml +83 -0
- package/rules/context-exfiltration/ATR-2026-02866-idna-label-separator-in-fetch-url-host.yaml +104 -0
- package/rules/excessive-autonomy/ATR-2026-00710-ipi-physical-access-grant.yaml +1 -1
- package/rules/model-abuse/ATR-2026-01897-host-sabotage.yaml +2 -2
- package/rules/model-security/ATR-2026-00433-modelcache-torch-load-deserialization-rce.yaml +1 -1
- package/rules/privilege-escalation/ATR-2026-00436-enclave-vm-sandbox-escape-rce.yaml +1 -1
- package/rules/privilege-escalation/ATR-2026-01601-sql-injection-destructive-ddl.yaml +2 -2
- package/rules/privilege-escalation/ATR-2026-01612-debug-mode-privilege-escalation.yaml +1 -1
- package/rules/privilege-escalation/ATR-2026-02867-identifier-typed-tool-argument-dot-dot-path-segment.yaml +106 -0
- package/rules/prompt-injection/ATR-2026-00004-system-prompt-override.yaml +2 -2
- package/rules/prompt-injection/ATR-2026-00080-encoding-evasion.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00086-visual-spoofing.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00203-context-pollution-skill-description.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00228-structured-jailbreak.yaml +2 -2
- package/rules/prompt-injection/ATR-2026-00233-structured-jailbreak.yaml +2 -2
- package/rules/prompt-injection/ATR-2026-00256-base-n-encoding-jailbreak.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00264-latent-injection-translation.yaml +3 -3
- package/rules/prompt-injection/ATR-2026-00265-latent-injection-rag-document.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00282-perez-prompt-injection-hijack.yaml +4 -4
- package/rules/prompt-injection/ATR-2026-00321-hyphenated-system-instruction-injection.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00394-backspace-deletion-character-injection.yaml +2 -2
- package/rules/prompt-injection/ATR-2026-00446-variable-assignment-payload-injection.yaml +3 -3
- package/rules/prompt-injection/ATR-2026-00476-garak-web-injection-javascript-alert-1.yaml +3 -3
- package/rules/prompt-injection/ATR-2026-00481-garak-dan-mixedunassigned.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00489-garak-encoding-javascript-alert-1.yaml +3 -3
- package/rules/prompt-injection/ATR-2026-00508-escape-delimiter-wrapped-goal-hijacking-in-user-input-prompt.yaml +3 -3
- package/rules/prompt-injection/ATR-2026-00512-rules-file-backdoor-injection.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-01005-many-shot-repetition-override.yaml +2 -2
- package/rules/prompt-injection/ATR-2026-01006-payload-split-string-concat-injection.yaml +2 -2
- package/rules/prompt-injection/ATR-2026-01015-evasion-refusal-suppression.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-01016-evasion-response-priming-forced-opener.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-01026-evasion-unicode-glitch-token-anomaly.yaml +2 -2
- package/rules/prompt-injection/ATR-2026-01304-indirect-injection-carrier-important-override.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-01759-dos-new-important-instructions-injection-in-document.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-01865-llmail-fake-email-boundary-marker.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-02010-emoji-only-payload.yaml +2 -2
- package/rules/prompt-injection/ATR-2026-02815-injected-halt-order-canned-reply-dos.yaml +80 -0
- package/rules/prompt-injection/ATR-2026-02820-tool-result-orders-agent-to-hide-its-own-action.yaml +106 -0
- package/rules/prompt-injection/ATR-2026-02858-context-suppression-directive.yaml +73 -0
- package/rules/prompt-injection/ATR-2026-02859-tool-output-agent-role-reassignment.yaml +71 -0
- package/rules/prompt-injection/ATR-2026-02860-forged-instruction-boundary-marker.yaml +70 -0
- package/rules/prompt-injection/ATR-2026-02862-fake-chat-template-turn-injection.yaml +79 -0
- package/rules/skill-compromise/ATR-2026-00060-skill-impersonation.yaml +1 -1
- package/rules/skill-compromise/ATR-2026-00063-skill-chain-attack.yaml +2 -2
- package/rules/skill-compromise/ATR-2026-00066-parameter-injection.yaml +2 -2
- package/rules/skill-compromise/ATR-2026-00149-skill-exfil-compound.yaml +6 -6
- package/rules/skill-compromise/ATR-2026-00223-reverse-shell-dropper.yaml +2 -2
- package/rules/skill-compromise/ATR-2026-01755-backdoor-pot-linguistic-trigger-phrase.yaml +1 -1
- package/rules/skill-compromise/ATR-2026-01756-backdoor-pot-symbol-emoticon-trigger.yaml +1 -1
- package/rules/skill-compromise/ATR-2026-02261-code-credential-exfil-chain.yaml +1 -1
- package/rules/tool-poisoning/ATR-2026-00012-unauthorized-tool-call.yaml +23 -23
- package/rules/tool-poisoning/ATR-2026-00013-tool-ssrf.yaml +16 -5
- package/rules/tool-poisoning/ATR-2026-00161-important-tag-cross-tool-shadowing.yaml +1 -1
- package/rules/tool-poisoning/ATR-2026-00277-echo-template-command-injection.yaml +2 -2
- package/rules/tool-poisoning/ATR-2026-00494-garak-exploitation-mixedunassigned.yaml +4 -4
- package/rules/tool-poisoning/ATR-2026-00581-mcp-tool-rug-pull-post-approval-redefinition.yaml +1 -1
- package/rules/tool-poisoning/ATR-2026-01303-tool-schema-enumeration-social-engineering.yaml +1 -1
- package/rules/tool-poisoning/ATR-2026-01307-mcp-dns-rebinding-attack.yaml +2 -2
- package/rules/tool-poisoning/ATR-2026-01775-semantic-mcp-tool-manifest-poisoning.yaml +1 -1
- package/rules/tool-poisoning/ATR-2026-01932-shadow-undeclared-mcp-server-registration.yaml +1 -1
- package/rules/tool-poisoning/ATR-2026-02025-mcp-full-schema-poisoning-nondescription-field.yaml +1 -1
- package/rules/tool-poisoning/ATR-2026-02817-untrusted-content-dictates-tool-arguments.yaml +83 -0
- package/rules/tool-poisoning/ATR-2026-02864-non-canonical-ipv4-host-in-url-tool-argument.yaml +102 -0
- package/rules/tool-poisoning/ATR-2026-02865-read-only-utility-write-flag-in-command-argument.yaml +157 -0
- package/rules/tool-poisoning/ATR-2026-02868-ssrf-ipv6-transition-address-embedded-private-ipv4.yaml +107 -0
- package/spec/README.md +6 -3
- package/spec/atr-event-v1.0.md +13 -8
- package/spec/atr-method-v1.1.md +2 -2
- package/spec/category-registry/gemara/README.md +102 -0
- package/spec/category-registry/gemara/ai-agent-capability-catalog.yaml +157 -0
- package/spec/category-registry/gemara/atr-attack-vector-catalog.yaml +130 -0
- package/spec/category-registry/gemara/atr-detection-control-catalog.yaml +327 -0
- package/spec/category-registry/gemara/atr-threat-catalog.yaml +246 -0
- package/spec/category-registry/gemara/src/editorial.yaml +743 -0
- package/spec/mappings/README.md +1 -1
- package/spec/mappings/atr-to-nist-csf-2.0.md +5 -4
- package/spec/schema/event.schema.json +1 -1
package/README.md
CHANGED
|
@@ -13,10 +13,9 @@ AI Agent 威脅偵測規則的開放格式
|
|
|
13
13
|
[](https://github.com/marketplace/actions/atr-scan)
|
|
14
14
|
[](LICENSE)
|
|
15
15
|
[](https://doi.org/10.5281/zenodo.19178002)
|
|
16
|
-
[](#5-specification)
|
|
17
17
|
[](#7-coverage)
|
|
18
18
|
[](#7-coverage)
|
|
19
|
-
[](#7-coverage)
|
|
20
19
|
[](https://opencollective.com/agent-threat-rules)
|
|
21
20
|
|
|
22
21
|
</div>
|
|
@@ -29,7 +28,7 @@ ATR (Agent Threat Rules) is an open detection rule format for AI agent security
|
|
|
29
28
|
|
|
30
29
|
## Status of This Document
|
|
31
30
|
|
|
32
|
-
ATR is published as a **Working Draft** at version `4.1.
|
|
31
|
+
ATR is published as a **Working Draft** at version `4.1.5`. The rule format defined in `SPEC.md` is stable and merged into open-source repos at Microsoft, Cisco, and Gen Digital, and integrated by community projects (MISP / CIRCL, OWASP Agent Security Regression Harness, SigmaHQ, FINOS Common Cloud Controls); full list with PR links in [§6 Adoption](#6-adoption). Governance is currently single-maintainer (BDFL) transitioning to a Technical Steering Committee per [GOVERNANCE.md](GOVERNANCE.md).
|
|
33
32
|
|
|
34
33
|
All numbers in this document are sourced from [`data/stats.json`](data/stats.json), which is the canonical record of the project's current state. Where this README and `stats.json` disagree, `stats.json` is authoritative.
|
|
35
34
|
|
|
@@ -156,6 +155,7 @@ Zero-install scan of the current directory; the image bundles the CLI and pulls
|
|
|
156
155
|
```bash
|
|
157
156
|
atr scan skill.md # scan a SKILL.md file
|
|
158
157
|
atr scan mcp-config.json # scan MCP server config / event log
|
|
158
|
+
atr scan tools.json # scan an MCP tools/list result, one event per tool
|
|
159
159
|
atr scan . --sarif > results.sarif
|
|
160
160
|
atr convert generic-regex # export rules as JSON (all patterns)
|
|
161
161
|
atr convert splunk # export to Splunk SPL
|
|
@@ -269,17 +269,20 @@ would be more dangerous than the request.
|
|
|
269
269
|
|
|
270
270
|
```bash
|
|
271
271
|
atr guard # advisory: report only (the default)
|
|
272
|
-
atr guard --lane enforce --blocking # blocking on, and only the
|
|
273
|
-
#
|
|
274
|
-
#
|
|
272
|
+
atr guard --lane enforce --blocking # blocking on, and only the live rules
|
|
273
|
+
# that are maturity: stable may fire
|
|
274
|
+
# (see the recall note below)
|
|
275
275
|
ATR_LANE=enforce ATR_BLOCKING=1 atr guard # the same, via the environment
|
|
276
276
|
```
|
|
277
277
|
|
|
278
278
|
**`--lane enforce` costs recall, and the cost is large.** It loads only
|
|
279
|
-
`maturity: stable` rules: **
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
279
|
+
`maturity: stable` rules: **103 of the 823 live rules** at ATR 4.1.5, and each
|
|
280
|
+
weekly measurement records the count it ran with as `rules_in_lane` in its
|
|
281
|
+
`breakdown.enforce_lane`. That is the trade being made every time enforcement is
|
|
282
|
+
recommended alongside it — narrower firing set, lower false-positive rate, fewer
|
|
283
|
+
attacks caught. What it still catches, per corpus, is the second (`enforce`)
|
|
284
|
+
figure in the `Recall` cells of [§8 Evaluation](#8-evaluation). Rule counts move
|
|
285
|
+
daily, and a
|
|
283
286
|
`grep`-based count is wrong here (eight rules quote the value as
|
|
284
287
|
`maturity: "stable"`), so re-derive by parsing before quoting the figure
|
|
285
288
|
anywhere:
|
|
@@ -299,9 +302,12 @@ PY
|
|
|
299
302
|
|
|
300
303
|
Programmatic embedding: `new ATREngine({ lane })` for the lane,
|
|
301
304
|
`new ActionExecutor({ adapter, blocking })` and
|
|
302
|
-
`new HookHandler({ engine, executor, blocking })` for enforcement
|
|
303
|
-
|
|
304
|
-
|
|
305
|
+
`new HookHandler({ engine, executor, blocking })` for enforcement, and
|
|
306
|
+
`new ATREngine({ modelDecisions })` for whether a match a model decided (a
|
|
307
|
+
semantic judge, the embedding signal, the semantic layer) may enforce; it is
|
|
308
|
+
advisory by default. **These are the only inputs** — the constructors ignore
|
|
309
|
+
`ATR_LANE`, `ATR_BLOCKING` and `ATR_MODEL_DECISIONS`, so setting them will not
|
|
310
|
+
configure an embedded engine. An unrecognised lane throws
|
|
305
311
|
a `TypeError`, and so does a non-boolean `blocking`: `blocking: "false"` is a
|
|
306
312
|
string, and every non-empty string is truthy, so it used to switch enforcement
|
|
307
313
|
**on** while reading as an explicit "off".
|
|
@@ -359,11 +365,11 @@ test_cases:
|
|
|
359
365
|
|
|
360
366
|
## 6. Adoption
|
|
361
367
|
|
|
362
|
-
|
|
368
|
+
Merged integrations, as of 2026-07-05 (every PR state re-verified against GitHub on that date):
|
|
363
369
|
|
|
364
370
|
| Organization | Integration | Reference |
|
|
365
371
|
|---|---|---|
|
|
366
|
-
| Microsoft Agent Governance Toolkit |
|
|
372
|
+
| Microsoft Agent Governance Toolkit | Example directories in the AGT repository (ATR import example, merged 2026-05-18; ACS annotator adapter example, merged 2026-06-15). The rule-pack YAML from the earlier example PRs (#908, #1277) was removed upstream on 2026-07-30 (AGT PR #3451). | [PR #3025](https://github.com/microsoft/agent-governance-toolkit/pull/3025) · [PR #2308](https://github.com/microsoft/agent-governance-toolkit/pull/2308) |
|
|
367
373
|
| Cisco AI Defense (skill-scanner) | Full rule pack merged into the open-source scanner repository (2026-04-22); original PoC (merged 2026-04-03). This is a merge into that repository, not a statement about any vendor product. | [PR #99](https://github.com/cisco-ai-defense/skill-scanner/pull/99) · [PR #79](https://github.com/cisco-ai-defense/skill-scanner/pull/79) |
|
|
368
374
|
| MISP (CIRCL) | Threat-intel cluster (galaxy, merged 2026-05-10) + rule-ID tagging vocabulary (taxonomies, merged 2026-05-10) | [galaxy #1207](https://github.com/MISP/misp-galaxy/pull/1207) · [taxonomies #323](https://github.com/MISP/misp-taxonomies/pull/323) |
|
|
369
375
|
| Gen Digital Sage (Norton / Avast / AVG parent) | Rule pack merged 2026-05-11 | [PR #33](https://github.com/gendigitalinc/sage/pull/33) |
|
|
@@ -376,13 +382,13 @@ Production deployments and standards-body integrations, as of 2026-07-05 (every
|
|
|
376
382
|
|
|
377
383
|
### Featured loop — Microsoft Copilot SWE Agent → ATR (2026-05-11)
|
|
378
384
|
|
|
379
|
-
On 2026-05-07 MSRC published two Semantic Kernel CVEs (CVE-2026-26030 lambda+eval RCE, CVE-2026-25592 autostart file write). On 2026-05-11 06:07 UTC, Microsoft Copilot SWE Agent opened [microsoft/agent-governance-toolkit#1981](https://github.com/microsoft/agent-governance-toolkit/pull/1981)
|
|
385
|
+
On 2026-05-07 MSRC published two Semantic Kernel CVEs (CVE-2026-26030 lambda+eval RCE, CVE-2026-25592 autostart file write). On 2026-05-10 the ATR maintainer filed [microsoft/agent-governance-toolkit#1937](https://github.com/microsoft/agent-governance-toolkit/issues/1937) mapping both CVEs to ATR rules. On 2026-05-11 06:07 UTC, after an AGT maintainer assigned that issue to it, Microsoft Copilot SWE Agent opened [microsoft/agent-governance-toolkit#1981](https://github.com/microsoft/agent-governance-toolkit/pull/1981), adding regression-test fixtures *presuming ATR detection* to the ATR community-rules example's test suite. By 08:24 UTC the same day, ATR v2.1.2 (rules ATR-2026-00440 + ATR-2026-00441) was merged, npm-published, and GitHub-released. PR open to rule merge: 2h 16m.
|
|
380
386
|
|
|
381
387
|
This is Microsoft Copilot operating inside AGT, not an MSRC endorsement. Coverage is partial: 2 of 4 Copilot fixtures match the v2.1.2 canonical regex shape.
|
|
382
388
|
|
|
383
389
|
### Under maintainer review (open PRs)
|
|
384
390
|
|
|
385
|
-
[NVIDIA
|
|
391
|
+
[NVIDIA NeMo Guardrails #2251](https://github.com/NVIDIA-NeMo/Guardrails/pull/2251) · [BerriAI LiteLLM #28050](https://github.com/BerriAI/litellm/pull/28050) · [promptfoo #8529](https://github.com/promptfoo/promptfoo/pull/8529) · [Cisco mcp-scanner #194](https://github.com/cisco-ai-defense/mcp-scanner/pull/194) · [Splunk security_content #4128](https://github.com/splunk/security_content/pull/4128) · [NIST OSCAL oscal-content #338](https://github.com/usnistgov/oscal-content/pull/338) (awaiting NIST review) · [OpenTelemetry semantic-conventions-genai #165](https://github.com/open-telemetry/semantic-conventions-genai/pull/165)
|
|
386
392
|
|
|
387
393
|
### Integrating ATR into your project
|
|
388
394
|
|
|
@@ -405,10 +411,10 @@ ATR maps its rules onto established frameworks so adopters can answer "we deploy
|
|
|
405
411
|
| Framework | Coverage | Mapping document |
|
|
406
412
|
|---|---|---|
|
|
407
413
|
| [OWASP Agentic Top 10 (2026)](https://genai.owasp.org/resource/owasp-top-10-for-agentic-applications-for-2026/) | 10/10 categories, 1,179 mappings across all 683 tagged rules | [docs/OWASP-AGENTIC-MAPPING.md](docs/OWASP-AGENTIC-MAPPING.md) |
|
|
408
|
-
| [
|
|
414
|
+
| [SAF-MCP](https://github.com/secure-agentic-framework/saf-mcp) (Framework Model v2) | 55 of 78 active techniques have at least one reviewed ATR rule (partial or adjacent); candidate mappings, not validated by SAF | [docs/SAFE-MCP-MAPPING.md](docs/SAFE-MCP-MAPPING.md) |
|
|
409
415
|
| [OWASP LLM Top 10 (2025)](https://owasp.org/www-project-top-10-for-large-language-model-applications/) | Per-rule references | Per-rule `references.owasp_llm` field |
|
|
410
416
|
| [MITRE ATLAS](https://atlas.mitre.org/) | Per-rule references | Per-rule `references.mitre_atlas` field |
|
|
411
|
-
| NIST AI RMF (community OSCAL catalog) |
|
|
417
|
+
| NIST AI RMF (community OSCAL catalog) | Per-rule subcategory mappings; community catalog, not endorsed by NIST | [Agent-Threat-Rule/ai-rmf-oscal-catalog](https://github.com/Agent-Threat-Rule/ai-rmf-oscal-catalog) |
|
|
412
418
|
| Five Eyes joint guidance (2026-05-01) | 5-category Careful-Adoption guidance → ATR's 10 categories | [docs/FIVE-EYES-MAPPING.md](docs/FIVE-EYES-MAPPING.md) |
|
|
413
419
|
|
|
414
420
|
### Detection categories
|
|
@@ -444,7 +450,9 @@ A full list lives in each rule's `references.cve` field. See [LIMITATIONS.md](LI
|
|
|
444
450
|
|
|
445
451
|
## 8. Evaluation
|
|
446
452
|
|
|
447
|
-
Every number below is a version-pinned, reproducible measurement
|
|
453
|
+
Every number in the table below is a version-pinned, reproducible measurement;
|
|
454
|
+
figures in the prose and footnotes are either quoted from those measurements or
|
|
455
|
+
are named one-off replays that say how they were produced. The full
|
|
448
456
|
historical series for each source lives at
|
|
449
457
|
[`data/measurements/<source>/`](data/measurements/) (immutable, append-only).
|
|
450
458
|
The current pointer per source is `data/measurements/<source>/latest.json`.
|
|
@@ -452,35 +460,75 @@ Aggregated into [`data/stats.json`](data/stats.json) under `benchmarks[]`.
|
|
|
452
460
|
|
|
453
461
|
| Source | Source version | Samples | Recall | Precision | FP rate | ATR version | Measured |
|
|
454
462
|
|---|---|---:|---:|---:|---:|---|---|
|
|
455
|
-
| AdvBench (LLM-attacks behaviors) | upstream-2026-
|
|
456
|
-
| atr-self-test | internal | 341 | 96.6% | 100.0% | 0.0% |
|
|
463
|
+
| AdvBench (LLM-attacks behaviors) | upstream-2026-10-15 | 520 | 5.6% (hunt) / 0.0% (enforce) | 100.0% | 0.0% | 4.1.5 | 2026-10-15 |
|
|
464
|
+
| atr-self-test | internal | 341 | 96.6% (hunt) / 3.4% (enforce) | 100.0% | 0.0% | 4.1.5 | 2026-10-15 |
|
|
457
465
|
| autoresearch | internal-1054 | 1,054 | 15.1% | 100.0% | 0.0% | 3.0.0-alpha.0 | 2026-05-23 |
|
|
458
|
-
| garak (in-the-wild jailbreaks) | inthewild-jailbreak-corpus-650 | 650 | 92.3% | 100.0% | 0.0% |
|
|
459
|
-
| garak-full (all probe families) | 23-families | 3,475 | 57.2% | 100.0% | 0.0% |
|
|
460
|
-
| hackaprompt | v1 | 4,780 |
|
|
461
|
-
| HarmBench (CAIS behaviors) | upstream-2026-
|
|
462
|
-
| hh-rlhf (Anthropic red-team-attempts) [^stdcorpora] | snapshot-2026-04 | 4,957 | 1.
|
|
463
|
-
| JailbreakBench (JBB-Behaviors) | upstream-2026-
|
|
464
|
-
| llm-guard (
|
|
465
|
-
| MITRE ATLAS [^stdcorpora] | snapshot-2026-04 | 182 |
|
|
466
|
-
| NeMo Guardrails (
|
|
467
|
-
| OWASP LLM Top 10 [^stdcorpora] | snapshot-2026-04 | 56 | 16.1% | 100.0% | 0.0% |
|
|
468
|
-
| PINT-format (deepset + Lakera Gandalf) [^pint] | v1 | 850 | 65.4% | 100.0% | 0.0% |
|
|
469
|
-
| PromptBench (academic adversarial) [^promptcorpora] | snapshot-2026-04 | 3,280 | 15.7% | 100.0% | 0.0% |
|
|
470
|
-
| promptfoo (
|
|
471
|
-
| PromptInject (academic adversarial) [^promptcorpora] | snapshot-2026-04 | 1,080 | 100.0% | 100.0% | 0.0% |
|
|
472
|
-
| SKILL.md benchmark (internal) [^skilllane] | internal-498 | 498 | 100.0% (hunt) / 0.0% (enforce) | 97.0% | 0.20% |
|
|
466
|
+
| garak (in-the-wild jailbreaks) [^garakcorpus] | inthewild-jailbreak-corpus-650 | 650 | 92.3% (hunt) / 0.9% (enforce) | 100.0% | 0.0% | 4.1.5 | 2026-10-15 |
|
|
467
|
+
| garak-full (all probe families) [^garakcorpus] | 23-families | 3,475 | 57.2% (hunt) / 0.5% (enforce) | 100.0% | 0.0% | 4.1.5 | 2026-10-15 |
|
|
468
|
+
| hackaprompt [^hackaprompt] | v1 | 4,780 | 83.1% (hunt) / 49.0% (enforce) | not cited [^hackaprompt] | not cited [^hackaprompt] | 4.1.5 | 2026-10-19 |
|
|
469
|
+
| HarmBench (CAIS behaviors) | upstream-2026-10-15 | 400 | 6.0% (hunt) / 0.0% (enforce) | 100.0% | 0.0% | 4.1.5 | 2026-10-15 |
|
|
470
|
+
| hh-rlhf (Anthropic red-team-attempts) [^stdcorpora] | snapshot-2026-04 | 4,957 | 1.4% (hunt) / 0.0% (enforce) | 100.0% | 0.0% | 4.1.5 | 2026-10-15 |
|
|
471
|
+
| JailbreakBench (JBB-Behaviors) | upstream-2026-10-15 | 100 | 3.0% (hunt) / 0.0% (enforce) | 100.0% | 0.0% | 4.1.5 | 2026-10-15 |
|
|
472
|
+
| llm-guard (2026-05-12 import) [^legacyvendor] | corpus-2026-05-12 | 44 | 63.6% (hunt) / 0.0% (enforce) | 100.0% | 0.0% | 4.1.5 | 2026-10-15 |
|
|
473
|
+
| MITRE ATLAS [^stdcorpora] | snapshot-2026-04 | 182 | 37.4% (hunt) / 1.1% (enforce) | 100.0% | 0.0% | 4.1.5 | 2026-10-15 |
|
|
474
|
+
| NeMo Guardrails (2026-05-12 import) [^legacyvendor] | corpus-2026-05-12 | 6 | 100.0% (hunt) / 0.0% (enforce) | 100.0% | 0.0% | 4.1.5 | 2026-10-15 |
|
|
475
|
+
| OWASP LLM Top 10 [^stdcorpora] | snapshot-2026-04 | 56 | 16.1% (hunt) / 0.0% (enforce) | 100.0% | 0.0% | 4.1.5 | 2026-10-15 |
|
|
476
|
+
| PINT-format (deepset + Lakera Gandalf) [^pint] | v1 | 850 | 65.4% (hunt) / 0.4% (enforce) | 100.0% | 0.0% | 4.1.5 | 2026-10-15 |
|
|
477
|
+
| PromptBench (academic adversarial) [^promptcorpora] | snapshot-2026-04 | 3,280 | 15.7% (hunt) / 0.0% (enforce) | 100.0% | 0.0% | 4.1.5 | 2026-10-15 |
|
|
478
|
+
| promptfoo (2026-05-12 import) [^legacyvendor] | corpus-2026-05-12 | 44 | 90.9% (hunt) / 6.8% (enforce) | 100.0% | 0.0% | 4.1.5 | 2026-10-15 |
|
|
479
|
+
| PromptInject (academic adversarial) [^promptcorpora] | snapshot-2026-04 | 1,080 | 100.0% (hunt) / 0.0% (enforce) | 100.0% | 0.0% | 4.1.5 | 2026-10-15 |
|
|
480
|
+
| SKILL.md benchmark (internal) [^skilllane] | internal-498 | 498 | 100.0% (hunt) / 0.0% (enforce) | 97.0% (hunt) | 0.20% (hunt) | 4.1.5 | 2026-10-15 |
|
|
481
|
+
| Vendor guardrail suites (pinned upstream tests) [^vendorsuites] | pinned-2026-10-19 | 146 | 77.0% (hunt) / 5.6% (enforce) | not cited [^vendorsuites] | not cited [^vendorsuites] | 4.1.5 | 2026-10-19 |
|
|
473
482
|
| Wild scan (OpenClaw + Skills.sh + Hermes + ClawHub) [^wildscan] | full-scan-v2-2026-04-13 | 101,280 | — | not measured | 1.42% flag rate | 2.0.0 | 2026-04-13 |
|
|
474
483
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
+
The `Vendor guardrail suites` row is the test cases of llm-guard, NeMo
|
|
485
|
+
Guardrails and promptfoo extracted by script from pinned upstream commits
|
|
486
|
+
([`data/test-corpora/vendor-guardrail-suites/`](data/test-corpora/vendor-guardrail-suites/README.md)).
|
|
487
|
+
It is partly in-sample: 16 rules name one of the three vendors or carry the
|
|
488
|
+
`(vendor-corpus-import)` tag. Its measurement file re-measures the same samples
|
|
489
|
+
without them (`breakdown.in_sample_ablation.without_rules_naming_source`), the
|
|
490
|
+
ablation reference to cite beside the row: 61.9% (hunt) / 5.6% (enforce) at
|
|
491
|
+
ATR 4.1.5, measured 2026-10-19. That is not an out-of-sample figure either; see
|
|
492
|
+
[^vendorsuites]. The weekly run does not re-measure this row:
|
|
493
|
+
`bash scripts/vendor-suites/reproduce.sh --write` does. The three
|
|
494
|
+
`2026-05-12 import` rows are the earlier hand-assembled corpora; not all of
|
|
495
|
+
their samples come from the vendor they name ([^legacyvendor]).
|
|
496
|
+
|
|
497
|
+
A `Recall` cell gives two figures from the same measurement file. The first is
|
|
498
|
+
the `hunt` lane: the engine default, which loads every maturity, and the figure
|
|
499
|
+
`latest.json` and `data/stats.json` carry. The second is the `enforce` lane, the
|
|
500
|
+
one to run when blocking is on, which loads only `stable` rules: the same
|
|
501
|
+
samples through the same detection loop, recorded as `breakdown.enforce_lane`.
|
|
502
|
+
Read the second before deploying with blocking on; see [^skilllane].
|
|
503
|
+
`autoresearch` shows only the first, because its last measurement predates
|
|
504
|
+
the second's recording, and `Wild scan` has no recall at all. `Precision` and `FP rate` are `hunt`-lane figures, measured only on the
|
|
505
|
+
rows that contain benign samples (`atr-self-test`, `PINT-format` and `SKILL.md
|
|
506
|
+
benchmark`); elsewhere they are convention values or, for `Wild scan`, a flag
|
|
507
|
+
rate, not results (see Conventions below).
|
|
508
|
+
|
|
509
|
+
Whether a corpus was used to write the rules it scores has been examined for
|
|
510
|
+
`garak`, `garak-full`, `PromptInject`, `PromptBench` ([^garakcorpus],
|
|
511
|
+
[^promptcorpora]) and `hackaprompt` ([^hackaprompt]); all five are partly
|
|
512
|
+
closed-book. For `hackaprompt`, 20 rules name HackAPrompt in their YAML,
|
|
513
|
+
several mined from this exact sample; the same measurement file re-runs the
|
|
514
|
+
samples without them (`breakdown.in_sample_ablation.without_rules_naming_source`),
|
|
515
|
+
the ablation reference to cite beside the row: 28.7% (hunt) / 0.7% (enforce)
|
|
516
|
+
at ATR 4.1.5, measured 2026-10-19. It approximates an out-of-sample figure; it
|
|
517
|
+
is not one. The other rows are not
|
|
518
|
+
thereby out-of-sample: `atr-self-test` is built partly from the rules' own true
|
|
519
|
+
positives, and the rules authored `(vendor-corpus-import)` name the `promptfoo`
|
|
520
|
+
and `llm-guard` fixtures as their source.
|
|
521
|
+
|
|
522
|
+
A weekly run re-measures every row except the following, which keep their
|
|
523
|
+
earlier measurements: `hackaprompt`, whose corpus (a gated HuggingFace dataset) is not
|
|
524
|
+
provisioned in CI, so the run skips it and the row is re-measured locally with
|
|
525
|
+
`npm run eval:hackaprompt`; `autoresearch`, an internal predicted-rule
|
|
526
|
+
corpus with no standalone runner; and the `Wild scan` snapshot. The table is
|
|
527
|
+
re-rendered from the measurement files; the prose and footnotes are not, so a
|
|
528
|
+
figure there holds for the version it names. Before the weekly run, every row
|
|
529
|
+
except `autoresearch` and the `Wild scan` had been (re-)measured against ATR
|
|
530
|
+
3.5.0 on 2026-06-16; the re-measurements since are described below, and
|
|
531
|
+
[^promptcorpora] covers what moved for `PromptInject` and `PromptBench`.
|
|
484
532
|
|
|
485
533
|
`PromptInject` and `PromptBench` were re-measured against ATR 3.5.2 on
|
|
486
534
|
2026-06-25 after a fix to the recall-analysis harness event shape; the prior
|
|
@@ -488,14 +536,55 @@ result.)
|
|
|
488
536
|
top-level field the engine does not read), not the engine's actual result.
|
|
489
537
|
`hh-rlhf`, `MITRE ATLAS` and `OWASP LLM Top 10` were re-measured against ATR
|
|
490
538
|
3.5.11 on 2026-08-05 after their runner was found never to have called the
|
|
491
|
-
engine at all — see [^stdcorpora].
|
|
492
|
-
100.0% → 39.0% and 100.0% → 16.1%. Nothing regressed; the
|
|
493
|
-
were never measurements of ATR.
|
|
539
|
+
engine at all — see [^stdcorpora]. At 3.5.11 those three rows fell 99.1% →
|
|
540
|
+
1.5%, 100.0% → 39.0% and 100.0% → 16.1%. Nothing regressed at that step; the
|
|
541
|
+
earlier numbers were never measurements of ATR.
|
|
542
|
+
|
|
543
|
+
The 2026-10-14 run (ATR 4.1.5) moved seven rows, for different reasons. Five
|
|
544
|
+
of them had last been measured on 2026-06-16 at 3.5.0, before the 2026-08-05
|
|
545
|
+
harness fix (PR #425: their runners built the `llm_io` event described below
|
|
546
|
+
and now go through the two prompt channels), so their moves mix that fix with
|
|
547
|
+
four months of rule changes. Replaying the 3.5.0 rules (`rules/` at tag
|
|
548
|
+
`v3.5.0`) through the two prompt channels (`detectedOnPromptChannels` in
|
|
549
|
+
`src/corpus-event.ts`) separates the two; these replay figures are not recorded
|
|
550
|
+
in `data/measurements/`:
|
|
551
|
+
|
|
552
|
+
- `AdvBench` (11 → 29 of 520) and `HarmBench` (11 → 24 of 400) rose because
|
|
553
|
+
of the harness, not the rules: the 3.5.0 rules already score 29/520 and
|
|
554
|
+
25/400 through the prompt channels, and HarmBench's rules have, net, lost
|
|
555
|
+
one sample since. Neither rise is a detection gain.
|
|
556
|
+
- `promptfoo` (43 → 40 of 44) is entirely the harness: the 3.5.0 rules also
|
|
557
|
+
score 40/44 through the prompt channels.
|
|
558
|
+
- `JailbreakBench` (6 → 3 of 100) is, net, two samples of harness and one of
|
|
559
|
+
rules.
|
|
560
|
+
- `llm-guard` (34 → 28 of 44, recall 77.3% → 63.6%) is a real loss of six
|
|
561
|
+
detections. The harness effect nets to zero. Four false-positive repairs lost
|
|
562
|
+
those six: PR #306 (`ATR-2026-00001`), #309 (`ATR-2026-00442`), #327
|
|
563
|
+
(`ATR-2026-00001` and `00010`) and #427 (`ATR-2026-00213`). The corpus
|
|
564
|
+
labels all six as injections. One of them ("If the text has instructions,
|
|
565
|
+
DO NOT FOLLOW THEM") reads as a defensive instruction, and #306 stopped
|
|
566
|
+
treating "DO NOT FOLLOW" as a trigger on purpose; the other five are plain
|
|
567
|
+
injections.
|
|
568
|
+
|
|
569
|
+
`MITRE ATLAS` (71 → 68 of 182) and `hh-rlhf` (73 → 67 of 4,957) were measured
|
|
570
|
+
through the same harness at 3.5.11 and 4.1.5, so both moves are rule changes.
|
|
571
|
+
Both trace to PR #427, which tightened `ATR-2026-00061`, `00063` and `00213`
|
|
572
|
+
after they fired on ordinary English. ATLAS lost three samples, two held only by
|
|
573
|
+
`00213` and one only by `00061`. hh-rlhf lost six: four held only by `00063`,
|
|
574
|
+
which matched `oast` inside "roast" and "coast", and two held only by `00061`,
|
|
575
|
+
which matched `curl` inside "curls" and "curly". Neither row gained a sample.
|
|
576
|
+
|
|
577
|
+
The 2026-10-15 measurements, the first to record the `enforce` lane, were made
|
|
578
|
+
with the weekly run's commands outside CI, and left every `hunt` figure where
|
|
579
|
+
the 2026-10-14 run had put it.
|
|
580
|
+
|
|
494
581
|
The per-row `ATR version` column above is the version each cell was actually
|
|
495
582
|
measured against, mirroring the `atr_version` field in each
|
|
496
583
|
`data/measurements/<source>/latest.json`. The headline `garak` recall moved
|
|
497
584
|
98.0% (3.0.0) → 97.2% (3.5.0) → 95.7% (3.5.8) → 92.5% (3.5.11) → 92.3%
|
|
498
|
-
(3.5.12)
|
|
585
|
+
(3.5.12); the 2026-10-14 and 2026-10-15 runs at 4.1.5 also gave 600/650. Read
|
|
586
|
+
that figure as partly closed-book: [^garakcorpus] replays it without the rules
|
|
587
|
+
written from this corpus. The 3.5.8 →
|
|
499
588
|
3.5.11 step is a real loss of detections, not a change in how they are counted:
|
|
500
589
|
PR #327 tightened an over-broad persona regex in `ATR-2026-00001` that had been
|
|
501
590
|
false-positiving on benign "you are now an expert …" prose, and tightening it
|
|
@@ -514,73 +603,148 @@ run exists anywhere in the repository. `data/measurements/garak/latest.json`
|
|
|
514
603
|
pointed, the entire time, at 95.7% measured on 3.5.8; `garak-full`'s pointed at
|
|
515
604
|
38.3% on 3.5.0, while a never-referenced 3.5.8 file sat unread in the same
|
|
516
605
|
directory. So the claims failed this project's own rule that every published
|
|
517
|
-
number is a version-pinned, reproducible measurement.
|
|
606
|
+
number is a version-pinned, reproducible measurement. The 91.5% was also produced by a harness
|
|
518
607
|
that built an event of `type: 'llm_io'`, which is a rule *source* and not an
|
|
519
608
|
`AgentEventType`; `src/engine.ts` could not map it and so ran every rule of
|
|
520
609
|
every source against the event instead of the two source types the harness
|
|
521
|
-
documented itself as using. The
|
|
522
|
-
2026-08-
|
|
523
|
-
|
|
610
|
+
documented itself as using. The figure that replaced them was first measured on
|
|
611
|
+
2026-08-05 at 780 rules (601/650) and re-measured on 2026-08-15 at 784 rules
|
|
612
|
+
(600/650, written to
|
|
524
613
|
`data/measurements/garak/2026-08-15_garak-inthewild-jailbreak-corpus-650_atr-3-5-12.json`
|
|
525
|
-
with the commit that produced it
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
614
|
+
with the commit that produced it), both through `llm_input` + `tool_response`,
|
|
615
|
+
the two channels `src/hook-handler.ts` can actually deliver a prompt on; every
|
|
616
|
+
`garak` measurement since, including the 2026-10-14 one at ATR 4.1.5, goes
|
|
617
|
+
through the same two channels. Under the wider shape set used for
|
|
618
|
+
false-positive measurement (which also runs `engine.scanSkill()`) the corpus
|
|
619
|
+
scores a little higher, 92.9% at both 3.5.12 and 4.1.5, recorded as
|
|
620
|
+
`wide_shape_recall` in each measurement's `breakdown`; that number is
|
|
621
|
+
deliberately not the published one, because a garak prompt never reaches
|
|
529
622
|
production as a SKILL.md. `.github/workflows/eval.yml` now runs
|
|
530
623
|
`scripts/check-benchmark-citations.ts`, which fails CI if this table or
|
|
531
624
|
`stats.json` cites a number no measurement file backs.
|
|
532
625
|
See [CHANGELOG.md](CHANGELOG.md).
|
|
533
626
|
|
|
534
|
-
[^skilllane]: **
|
|
535
|
-
|
|
536
|
-
maturity.
|
|
537
|
-
the agent with no human in the loop —
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
627
|
+
[^skilllane]: **The first figure in each `Recall` cell is the `hunt` lane, and
|
|
628
|
+
the lane can change the answer completely.** `hunt` is the engine default
|
|
629
|
+
and loads every maturity. The `enforce` lane — the one to run when blocking
|
|
630
|
+
is on, where a detection can stop the agent with no human in the loop —
|
|
631
|
+
loads only `stable` rules, and its figure is the second one in the cell.
|
|
632
|
+
Since 2026-10-15 every measurement records it as `breakdown.enforce_lane`
|
|
633
|
+
in the same file as the headline: the same samples through the
|
|
634
|
+
benchmark's own detection loop (`engine.scanSkill()` for SKILL.md, the two
|
|
635
|
+
prompt channels for `garak`), on `new ATREngine({ lane: 'enforce' })`, with
|
|
636
|
+
`rules_in_lane` giving how many rules that lane loaded. It counts
|
|
637
|
+
detections, and a detection is not necessarily a block: the verdict blocks
|
|
638
|
+
only on severity and confidence (`src/verdict.ts`), so the figure is an
|
|
639
|
+
upper bound on what blocking stops.
|
|
640
|
+
`scripts/check-benchmark-citations.ts` fails CI when a cell's enforce
|
|
641
|
+
figure differs from that record or is left out. For SKILL.md the low figure
|
|
642
|
+
is structural rather than a tuning problem: at ATR 4.1.5 all 39 rules
|
|
643
|
+
carrying `scan_target: skill` are `maturity: test` and none is
|
|
644
|
+
`maturity: stable`, so
|
|
645
|
+
the enforce lane loads none of the rules written specifically for SKILL.md
|
|
646
|
+
files. Anyone reading "100% recall on SKILL.md" and deploying with
|
|
647
|
+
blocking on would be forming a completely wrong expectation. Until
|
|
648
|
+
2026-10-15 the weekly run measured only the `hunt` lane, and the enforce
|
|
649
|
+
figures this footnote quoted were one-off replays.
|
|
545
650
|
|
|
546
651
|
[^pint]: The `PINT-format` row is **not** a run of Lakera's official PINT
|
|
547
652
|
benchmark. That corpus is private and roughly 5x larger; this row is a
|
|
548
653
|
self-built 850-sample corpus in PINT's format, assembled from
|
|
549
654
|
`deepset/prompt-injections` (660) and `Lakera/gandalf_ignore_instructions`
|
|
550
|
-
(190). It also carries a scope caveat worth stating plainly:
|
|
551
|
-
784 rules**
|
|
552
|
-
of the 295 detections. The eval report
|
|
655
|
+
(190). It also carries a scope caveat worth stating plainly: at 3.5.12 only
|
|
656
|
+
**62 of 784 rules** fired on it at all, and `ATR-2026-00001` alone
|
|
657
|
+
accounted for 226 of the 295 detections. The 3.5.12 eval report
|
|
658
|
+
(`data/pint-benchmark/pint-eval-report.json`) listed 63 per-rule entries,
|
|
553
659
|
but one of those is `tier2.5-embedding-match` — the Tier 2.5 embedding
|
|
554
660
|
stage, not a rule. Read it as a prompt-injection-family score, not as
|
|
555
661
|
ATR's overall coverage. The row moved 63.6% → 60.3% between 3.5.0 and
|
|
556
662
|
3.5.11 for the same reason `garak` moved: PR #327 tightened
|
|
557
663
|
`ATR-2026-00001`'s persona-switch regex to stop it false-positiving on
|
|
558
|
-
benign prose.
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
664
|
+
benign prose. Through 3.5.11 the runner used a legacy event shape under
|
|
665
|
+
which the engine's source-type filter dropped every non-`llm_io` rule
|
|
666
|
+
before matching, so those figures, precision included, were measured over
|
|
667
|
+
roughly half the rulebase. The rise to 65.4% at 3.5.12 (2026-08-15) is
|
|
668
|
+
that harness changing, not the rules: that run was the first through the
|
|
669
|
+
canonical shape (PR #427), which admits every rule. Replayed through the
|
|
670
|
+
canonical shape, the 3.5.11 rules score 300 detections against 272 under
|
|
671
|
+
the legacy shape (the published 3.5.11 figure), so the rules changed
|
|
672
|
+
between 3.5.11 and 3.5.12 lost five detections on this corpus, while
|
|
673
|
+
`ATR-2026-00001`'s own contribution stayed at 226. Precision on the
|
|
674
|
+
canonical shape at 3.5.12 was 100% (0 FP on the 399 benign samples).
|
|
675
|
+
|
|
676
|
+
[^garakcorpus]: **Read this row as partly closed-book.** At ATR 4.1.5 (the rules
|
|
677
|
+
on `main` at `32bd48966`, 830 rule files), many of the rules that fire on
|
|
678
|
+
this corpus had been written from it, so its `hunt` figure is not an
|
|
679
|
+
out-of-sample result. A rule is counted as written from the corpus when its
|
|
680
|
+
own YAML shows the link, in either of two ways. 102 rules name the corpus in
|
|
681
|
+
their author, title, description or references (matching
|
|
682
|
+
`/inthewild|daninthewild|in-the-wild (jailbreak|corpus)/i`): an `author` of
|
|
683
|
+
`ATR Community (via NVIDIA garak in-the-wild corpus)` or
|
|
684
|
+
`(via NVIDIA garak dan.DanInTheWild probe)` — garak's `dan.DanInTheWild`
|
|
685
|
+
probes draw their prompts from this corpus — or, for example,
|
|
686
|
+
`ATR-2026-00307`, whose description cites `inthewild_jailbreak_llms.json`.
|
|
687
|
+
28 more give garak as their source in their `author` (22
|
|
688
|
+
`ATR Community (garak-import)`, 4 `(via NVIDIA garak dan probe)`, 2
|
|
689
|
+
`(via ATR garak pipe)`) and quote one of these 650 prompts in their own
|
|
690
|
+
true-positive test cases: 60 or more consecutive characters, compared after
|
|
691
|
+
lower-casing and collapsing whitespace. Of the 130, 126 fire here, and 175
|
|
692
|
+
of the 600 prompts the full rule set detected were detected by them alone.
|
|
693
|
+
**Replayed without them, recall on the same 650 prompts was 65.4% (425 of
|
|
694
|
+
650).** Without only the 102 that name the corpus, it was 81.5% (530 of
|
|
695
|
+
650). A looser reading goes lower. `ATR-2026-00003`, a generic DAN rule in
|
|
696
|
+
ATR since v0.1.0 (2026-03-09), before any rule here was written from garak,
|
|
697
|
+
also quotes this corpus: one of its test cases is the public DAN opener,
|
|
698
|
+
which 7 of these prompts contain. It detects 259 of the 650, almost all of
|
|
699
|
+
them without that text, so it is not counted; counting it gave 51.8% (337
|
|
700
|
+
of 650). Two rules authored `(via NVIDIA garak dan probe)` neither name nor
|
|
701
|
+
quote the corpus (`ATR-2026-00273` and `00304` cite garak's DAN templates);
|
|
702
|
+
counting them too would move 65.4% to 64.9%, by arithmetic over the full
|
|
703
|
+
run's per-prompt matches rather than by a replay. The other figures are
|
|
704
|
+
**replays**, not measurements: each was run once, on 2026-10-15, with the
|
|
705
|
+
rule files removed from a copy of `rules/` and every prompt sent through the
|
|
706
|
+
two channels the published figure uses (`llm_input` and `tool_response`, as
|
|
707
|
+
`scripts/eval-garak-inthewild.ts` does). Nothing in `data/measurements/`
|
|
708
|
+
records them, and nothing refreshes them. None of the 130 is
|
|
709
|
+
`maturity: stable`, so the `enforce` figure does not rest on them.
|
|
710
|
+
`garak-full` contains these 650 prompts twice; see the paragraph on the two
|
|
711
|
+
`garak` rows below.
|
|
712
|
+
|
|
713
|
+
[^promptcorpora]: **Read both of these as closed-book scores.** Both rows are
|
|
714
|
+
measured on a legacy event, `{ type: 'llm_io', content,
|
|
715
|
+
fields.user_input }`. `llm_io` is a rule source, not an event type the
|
|
716
|
+
engine can route, so source filtering is off and every rule of every
|
|
717
|
+
source runs, on only those two fields. The other prompt-corpus rows
|
|
718
|
+
(`garak`, `AdvBench`, `HarmBench`, `JailbreakBench`, `llm-guard`,
|
|
719
|
+
`NeMo Guardrails` and `promptfoo`) go through the two prompt channels
|
|
720
|
+
instead. Each measurement's `breakdown.attribution.canonical_shapes` gives
|
|
721
|
+
the same corpus on the wider shape set the benign false-positive gate uses,
|
|
722
|
+
which also runs `engine.scanSkill()`; there PromptBench scores 54.8%, 1,633
|
|
723
|
+
of its 1,798 detections coming from one tool-argument rule,
|
|
724
|
+
`ATR-2026-00066`. That figure is deliberately not the published one, for
|
|
725
|
+
the reason given for `garak` above. Until 2026-08-05 the harness
|
|
726
|
+
recorded its per-rule breakdown as the literal string `"unknown"` (it read
|
|
727
|
+
`m.rule_id` off an engine match that carries `m.rule.id`), so no published
|
|
728
|
+
version of these rows could say which rules produced them. With
|
|
729
|
+
attribution restored, at 3.5.11:
|
|
730
|
+
**PromptInject 100.0%** was produced by **7 of 780 rules**. Five of those
|
|
571
731
|
seven — `ATR-2026-00506`, `00507`, `00508`, `00509`, `00518` — carry
|
|
572
732
|
`author: ATR Community (PromptInject corpus)`: they were written *from*
|
|
573
733
|
this corpus, which has four attack classes built from a handful of
|
|
574
|
-
templates. Remove those five and recall on the same 1,080 samples
|
|
575
|
-
**9.7%**. The concentration
|
|
576
|
-
(`ATR-2026-00508`, 968/1,080 samples)
|
|
577
|
-
them, so deleting it
|
|
578
|
-
`00507` (27)
|
|
579
|
-
gate, `00506` / `00507` / `00518`
|
|
580
|
-
`ATR-2026-00001` 19, `ATR-2026-00400` 1.
|
|
581
|
-
|
|
734
|
+
templates. Remove those five and recall on the same 1,080 samples was
|
|
735
|
+
**9.7%**. The concentration was real but not fragile: the top rule
|
|
736
|
+
(`ATR-2026-00508`, 968/1,080 samples) was the sole detector on none of
|
|
737
|
+
them, so deleting it left recall at 100%; only `00518` (45 samples) and
|
|
738
|
+
`00507` (27) were sole detectors of anything. On the 5,352-sample benign
|
|
739
|
+
gate, `00506` / `00507` / `00518` were 0-FP; `00508` had 4 FP, `00509` 3,
|
|
740
|
+
`ATR-2026-00001` 19, `ATR-2026-00400` 1. At 4.1.5 nine rules fire on
|
|
741
|
+
PromptInject. One of them, `ATR-2026-02846`, was added since and was
|
|
742
|
+
authored from PromptInject attack clusters (its title says so); it matches
|
|
743
|
+
780 of the 1,080 samples, so at 4.1.5 the closed-book figure needs it
|
|
744
|
+
removed as well as the five above.
|
|
745
|
+
**PromptBench 15.7%** was produced by **3 of 780 rules** (`ATR-2026-00520`,
|
|
582
746
|
`00519`, `00202`), all three 0-FP on the same benign gate. Two of the three
|
|
583
|
-
were mined from PromptBench; without them recall
|
|
747
|
+
were mined from PromptBench; without them recall was **2.4%**.
|
|
584
748
|
The PromptBench row moved 23.2% (3.5.2) → 15.7% (3.5.11) and the loss is
|
|
585
749
|
fully attributable: 247 samples were held only by rules that have since
|
|
586
750
|
been precision-repaired, and re-running each rule version by version pins
|
|
@@ -596,6 +760,38 @@ See [CHANGELOG.md](CHANGELOG.md).
|
|
|
596
760
|
columns are properties of the corpus, not measurements — read them
|
|
597
761
|
together with the benign-gate FP counts above, never alone.
|
|
598
762
|
|
|
763
|
+
[^vendorsuites]: **Partly in-sample; precision not cited.** 126 attack and 20
|
|
764
|
+
benign test cases (llm-guard 46 / 16, NeMo Guardrails 22 / 4, promptfoo 58 / 0),
|
|
765
|
+
each traceable to repo, commit, path and line in
|
|
766
|
+
[`manifest.json`](data/test-corpora/vendor-guardrail-suites/manifest.json). At ATR
|
|
767
|
+
4.1.5 (measured 2026-10-19) recall is 97/126 (hunt), 92/126 (alert) and 7/126
|
|
768
|
+
(enforce). Without the 16 rules whose YAML names promptfoo, llm-guard or NeMo, or
|
|
769
|
+
carries the `(vendor-corpus-import)` tag, it is 78/126 = 61.9% (hunt), 70/126 =
|
|
770
|
+
55.6% (alert) and 7/126 = 5.6% (enforce); per vendor in the hunt lane, llm-guard
|
|
771
|
+
26/46, NeMo Guardrails 20/22, promptfoo 32/58. That ablation is the reference
|
|
772
|
+
to cite beside the row, and it still overstates out-of-sample recall, by an
|
|
773
|
+
amount the same file measures (`breakdown.overlaps`): 35 further rules carry a
|
|
774
|
+
40-character run of some vendor sample's text in their YAML, and 23 of the 78
|
|
775
|
+
hunt-lane detections in the ablation are by such a rule on the sample it
|
|
776
|
+
overlaps; removing those rules too gives 58/126 = 46.0% (hunt) / 5/126 = 4.0%
|
|
777
|
+
(enforce). Five NeMo Guardrails attack samples (DAN-style jailbreaks) share 58%
|
|
778
|
+
to 99% of their text with a prompt in `garak-full`'s `dan.json` and
|
|
779
|
+
`inthewild.json`, a corpus other rules were mined from; all five are detected in
|
|
780
|
+
the hunt lane of the ablation. The vendors ship only 20 benign cases (the hunt
|
|
781
|
+
lane flags 1, the enforce lane 0), too few for a precision or FP-rate claim, so
|
|
782
|
+
the cells say "not cited" and `data/stats.json` carries `null` for both
|
|
783
|
+
(`breakdown.precision_not_citable`).
|
|
784
|
+
|
|
785
|
+
[^legacyvendor]: These three rows are the corpora assembled by hand on
|
|
786
|
+
2026-05-12 and attributed to the vendors' test suites. A script-based audit
|
|
787
|
+
([`legacy-corpora-provenance.json`](data/test-corpora/vendor-guardrail-suites/legacy-corpora-provenance.json))
|
|
788
|
+
checked each of their 94 samples against the vendor repo it names, at a pinned
|
|
789
|
+
commit: 79 occur verbatim in the vendor file they name, 3 are truncated or
|
|
790
|
+
edited from it, 2 are another vendor's test cases, and 10 are not found
|
|
791
|
+
verbatim anywhere in the vendor repository at the pinned commit. Read them as ATR-assembled corpora seeded from vendor tests, not as the
|
|
792
|
+
vendors' fixtures; the `Vendor guardrail suites` row is the script-extracted
|
|
793
|
+
replacement.
|
|
794
|
+
|
|
599
795
|
[^stdcorpora]: Until 2026-08-05 these three rows were **not produced by the ATR
|
|
600
796
|
engine**. `scripts/eval-std-corpora.ts` walked `rules/` with a YAML parser,
|
|
601
797
|
kept only `operator: regex` conditions, flattened every condition of every
|
|
@@ -617,56 +813,72 @@ See [CHANGELOG.md](CHANGELOG.md).
|
|
|
617
813
|
and the canonical event shapes in `scripts/lib/corpus-event.ts` — the same
|
|
618
814
|
entry point the false-positive gates use. Reproduce with
|
|
619
815
|
`npx tsx scripts/eval-std-corpora.ts`. Read the new numbers with the same
|
|
620
|
-
scope caveat as `PINT-format`: on ATLAS, `ATR-2026-00061` alone
|
|
621
|
-
for 59 of the 71 detections (32.4% of the corpus
|
|
816
|
+
scope caveat as `PINT-format`: on ATLAS at 3.5.11, `ATR-2026-00061` alone
|
|
817
|
+
accounted for 59 of the 71 detections (32.4% of the corpus; 58 of 68 at
|
|
818
|
+
4.1.5), and ATLAS procedures are
|
|
622
819
|
prose *descriptions* of attacks rather than attack payloads, so this row
|
|
623
820
|
measures ATR against attack write-ups, not against traffic.
|
|
624
821
|
|
|
625
|
-
Two `garak` rows are deliberate
|
|
626
|
-
in-the-wild jailbreak corpus (narrow
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
822
|
+
Two `garak` rows are deliberate, and they are not independent. The headline
|
|
823
|
+
`garak` source tracks NVIDIA's in-the-wild jailbreak corpus (narrow; this is the
|
|
824
|
+
number ATR cites publicly, and [^garakcorpus] gives how much of it rests on
|
|
825
|
+
rules written from that corpus). `garak-full` runs every non-empty family file
|
|
826
|
+
extracted from upstream garak (23 at ATR 4.1.5), and it contains the
|
|
827
|
+
in-the-wild corpus twice: as its `inthewild` family, and as 648 of the 664
|
|
828
|
+
prompts of its `dan` family. In the 2026-10-15 measurement those two families
|
|
829
|
+
supplied 1,214 of its 1,987 `hunt` detections. Rules have also been written
|
|
830
|
+
from most of its other families (an `author` of
|
|
831
|
+
`ATR Community (via NVIDIA garak <family> probe)`, 12 of them from `badchars`,
|
|
832
|
+
`dra` and `encoding`), so read `garak-full` as partly closed-book too.
|
|
833
|
+
[docs/RULE-PRODUCTION.md](docs/RULE-PRODUCTION.md) §2.3–2.4 covers its other
|
|
834
|
+
limits: six of its families are content-safety and hallucination probes, four
|
|
835
|
+
are the same 16 unencoded seed sentences, and 2,739 of its 3,475 prompts are
|
|
836
|
+
distinct. The two are kept as separate streams so neither figure stands in for
|
|
837
|
+
the other.
|
|
838
|
+
|
|
839
|
+
The low recall on AdvBench / HarmBench / JailbreakBench / hh-rlhf is
|
|
635
840
|
honest and expected. Those four corpora test **LLM safety alignment** (does the
|
|
636
841
|
model refuse harmful requests like "explain how to make a bomb"), not
|
|
637
842
|
**prompt-injection detection** (the surface ATR's regex layer targets).
|
|
638
|
-
ATR's
|
|
639
|
-
|
|
640
|
-
|
|
843
|
+
ATR's low recall on these corpora is consistent with the layering view
|
|
844
|
+
(this section does not measure what any other layer catches): regex catches
|
|
845
|
+
structured attack patterns, alignment + content moderation catch
|
|
846
|
+
natural-language harm requests. The numbers are recorded for
|
|
641
847
|
completeness and so any future ATR rule additions in the harm-category
|
|
642
848
|
space can be measured against a documented baseline. `hh-rlhf` is Anthropic's
|
|
643
|
-
red-team-attempts set — the same genre as the other three — and its
|
|
644
|
-
|
|
849
|
+
red-team-attempts set — the same genre as the other three — and its
|
|
850
|
+
low recall now sits with theirs instead of contradicting them at
|
|
851
|
+
99.1%.
|
|
645
852
|
|
|
646
853
|
Conventions: 100%-adversarial corpora contain no benign samples, so they have
|
|
647
854
|
no true-negative population and **`precision` and `fp_rate` cannot be computed
|
|
648
855
|
from them**. The measurement schema requires numbers, so those rows record the
|
|
649
856
|
convention `precision 1` / `fp_rate 0`. Read the `Precision` and `FP rate`
|
|
650
|
-
columns as "not applicable to this corpus", not as results
|
|
651
|
-
precision numbers
|
|
652
|
-
no ground-truth labels either; its
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
857
|
+
columns as "not applicable to this corpus", not as results. No benign-gate
|
|
858
|
+
precision numbers are published at present: the lane FP rates once quoted are
|
|
859
|
+
withdrawn (see below). Wild-scan has no ground-truth labels either; its
|
|
860
|
+
`Precision` cell reads `not measured` because the precision floor once
|
|
861
|
+
published for it is withdrawn (see [^wildscan]), and its `FP rate` cell is a
|
|
862
|
+
flag rate, flagged divided by scanned, not a false-positive rate. Every cell
|
|
863
|
+
except the `Wild scan` row (taken from the raw scan file; see [^wildscan]) is
|
|
864
|
+
sourced from a specific measurement file: `data/measurements/<source>/latest.json`
|
|
865
|
+
names it, and `benchmarks[].measurement_file` in `data/stats.json` gives its
|
|
866
|
+
path.
|
|
657
867
|
|
|
658
868
|
False-positive rate is lane-keyed as of v3.5.0, not a single overall figure.
|
|
659
869
|
ATR ships detection lanes (`enforce` / `alert` / `hunt`). The specific lane FP
|
|
660
870
|
rates previously quoted here are withdrawn and awaiting re-measurement — see
|
|
661
|
-
the note in the lanes section above for why.
|
|
662
|
-
|
|
871
|
+
the note in the lanes section above for why. Where a row has benign samples
|
|
872
|
+
(`atr-self-test`, `PINT-format`, `SKILL.md benchmark`), its `FP rate` cell is a
|
|
873
|
+
`hunt`-lane measurement; on every other row it is a convention value or, for
|
|
874
|
+
`Wild scan`, a flag rate. See [CHANGELOG.md](CHANGELOG.md)
|
|
663
875
|
(v3.5.0) for the lane definitions.
|
|
664
876
|
|
|
665
877
|
```bash
|
|
666
878
|
npm test # engine + rule unit tests (vitest)
|
|
667
879
|
npm run eval # atr-self-test eval (writes a measurement)
|
|
668
880
|
npm run eval:pint # PINT benchmark (writes a measurement)
|
|
669
|
-
|
|
881
|
+
npm run eval:hackaprompt # HackAPrompt (gated dataset; writes a measurement)
|
|
670
882
|
npx tsx src/eval/skill-benchmark.ts # SKILL.md (498 labeled)
|
|
671
883
|
npx tsx scripts/eval-std-corpora.ts # HH-RLHF + OWASP + ATLAS
|
|
672
884
|
npx tsx scripts/atr_recall_analysis.ts # PromptBench + PromptInject
|
|
@@ -681,9 +893,27 @@ npx tsx scripts/sync-stats-from-measurements.ts # r
|
|
|
681
893
|
|
|
682
894
|
Raw data: [`data/full-scan-v2-2026-04-14.json`](data/full-scan-v2-2026-04-14.json) — 101,280 skills scanned, 1,434 flagged, engine 2.0.0, timestamped 2026-04-13. The malware-campaign write-up is in [`docs/research/openclaw-malware-campaign-2026-04.md`](docs/research/openclaw-malware-campaign-2026-04.md).
|
|
683
895
|
|
|
896
|
+
[^hackaprompt]: **Partly in-sample; cite the ablation reference beside it.**
|
|
897
|
+
The samples are a seeded subset of 4,780 of the dataset's 601,757 rows
|
|
898
|
+
(`hackaprompt/hackaprompt-dataset` at revision `25b87fbe`, parquet sha256
|
|
899
|
+
`bedca308...`, seed 20260511, rows shorter than 3 characters dropped), pinned
|
|
900
|
+
by row indices and digests in
|
|
901
|
+
[`hackaprompt-corpus.manifest.json`](data/hackaprompt/hackaprompt-corpus.manifest.json);
|
|
902
|
+
`npm run eval:hackaprompt` re-draws it and stops on any mismatch. At ATR 4.1.5
|
|
903
|
+
(measured 2026-10-19) recall is 3,972 (hunt), 3,931 (alert) and 2,343
|
|
904
|
+
(enforce) of 4,780. Without the 20 rules whose YAML names HackAPrompt it is
|
|
905
|
+
1,372 = 28.7% (hunt) / 32 = 0.7% (enforce): the ablation reference, an
|
|
906
|
+
approximation of out-of-sample recall that does not guarantee it (a rule that
|
|
907
|
+
does not name HackAPrompt can still have been tuned on these prompts). The
|
|
908
|
+
corpus has no benign samples, so precision and FP rate are undefined on it:
|
|
909
|
+
the cells say "not cited" and `data/stats.json` carries `null` for both
|
|
910
|
+
(`breakdown.precision_not_citable`). Earlier figures for this row (28.6% → 66.2% in the 2.2.0 CHANGELOG
|
|
911
|
+
entry, 69.6% at ATR 3.5.0) and their re-runs are in
|
|
912
|
+
[`data/hackaprompt/METHOD.md`](data/hackaprompt/METHOD.md).
|
|
913
|
+
|
|
684
914
|
[^wildscan]: Scanned and flagged counts come from `total_scanned` and `total_flagged` in the raw scan file; the flag rate is those two divided. **No precision figure is given because none was measured over this run.** Earlier material paired a manual-review count against a smaller 96,096-skill analysis subset and reported the ratio as a precision floor. The review covered that subset rather than all 1,434 flags, so the ratio does not describe this scan and is not reproducible from the raw file; it has been withdrawn rather than recomputed. Establishing precision here means re-reviewing a sample of the 1,434 flags, which has not been done.
|
|
685
915
|
|
|
686
|
-
ATR is honest about what it cannot detect. Regex catalogs miss paraphrased attacks, semantic rephrasings of credential exfiltration, and novel attack shapes not present in the training corpus. `PromptBench` (3,280 character- and word-level robustness perturbations) is a different threat class from prompt injection and sits largely outside ATR's content scope; ATR
|
|
916
|
+
ATR is honest about what it cannot detect. Regex catalogs miss paraphrased attacks, semantic rephrasings of credential exfiltration, and novel attack shapes not present in the training corpus. `PromptBench` (3,280 character- and word-level robustness perturbations) is a different threat class from prompt injection and sits largely outside ATR's content scope; most of what ATR matches there comes from two rules mined from PromptBench itself, and the share fell from 23.2% at 3.5.2; [^promptcorpora] covers both. See [LIMITATIONS.md](LIMITATIONS.md) for the documented evasion-test corpus (64 techniques as of 2026-05) and the layering recommendation: ATR is the content layer; pair with credential brokering, sandbox execution, and human-in-the-loop for high-blast-radius actions.
|
|
687
917
|
|
|
688
918
|
## 9. Governance
|
|
689
919
|
|
|
@@ -693,7 +923,7 @@ ATR is currently single-maintainer (BDFL) under Adam Lin, transitioning to a Tec
|
|
|
693
923
|
|---|---|
|
|
694
924
|
| Phase 0 — Core spec, reference engine, initial rule corpus | Done |
|
|
695
925
|
| Phase 1 — Distribution surfaces (npm, PyPI, GitHub Action, SARIF, MCP server) | Done |
|
|
696
|
-
| Phase 2 —
|
|
926
|
+
| Phase 2 — Downstream integrations (Cisco skill-scanner, MISP, Gen Digital Sage, Microsoft AGT examples) | In progress |
|
|
697
927
|
| Phase 3 — Community contribution flywheel (issue-to-proposal automation, CVE-collector pipeline) | In progress |
|
|
698
928
|
| Phase 4 — TSC seating; second-engine implementation; submission to a standards body | Planned |
|
|
699
929
|
|
|
@@ -797,7 +1027,7 @@ ATR is released under the [MIT License](LICENSE). All contributions are MIT-lice
|
|
|
797
1027
|
|
|
798
1028
|
## 17. Acknowledgments
|
|
799
1029
|
|
|
800
|
-
ATR's design draws on prior work in: [Sigma](https://github.com/SigmaHQ/sigma) (SIEM detection format), [YARA](https://github.com/VirusTotal/yara) (malware signature format), [OWASP LLM Top 10](https://owasp.org/www-project-top-10-for-large-language-model-applications/), [OWASP Agentic Top 10](https://genai.owasp.org/resource/owasp-top-10-for-agentic-applications-for-2026/), [MITRE ATLAS](https://atlas.mitre.org/), [NVIDIA garak](https://github.com/NVIDIA/garak), [Lakera PINT](https://github.com/lakeraai/pint-benchmark), [Meta LlamaFirewall](https://ai.meta.com/research/publications/llamafirewall-an-open-source-guardrail-system-for-building-secure-ai-agents/), and [
|
|
1030
|
+
ATR's design draws on prior work in: [Sigma](https://github.com/SigmaHQ/sigma) (SIEM detection format), [YARA](https://github.com/VirusTotal/yara) (malware signature format), [OWASP LLM Top 10](https://owasp.org/www-project-top-10-for-large-language-model-applications/), [OWASP Agentic Top 10](https://genai.owasp.org/resource/owasp-top-10-for-agentic-applications-for-2026/), [MITRE ATLAS](https://atlas.mitre.org/), [NVIDIA garak](https://github.com/NVIDIA/garak), [Lakera PINT](https://github.com/lakeraai/pint-benchmark), [Meta LlamaFirewall](https://ai.meta.com/research/publications/llamafirewall-an-open-source-guardrail-system-for-building-secure-ai-agents/), and [SAF-MCP](https://github.com/secure-agentic-framework/saf-mcp).
|
|
801
1031
|
|
|
802
1032
|
The 2026-04 ecosystem-wide skill scan was made possible by the maintainers of OpenClaw, Skills.sh, Hermes Agent, and ClawHub publishing their registries openly.
|
|
803
1033
|
|
|
@@ -814,7 +1044,7 @@ The 2026-04 ecosystem-wide skill scan was made possible by the maintainers of Op
|
|
|
814
1044
|
- [OWASP Agentic Top 10 (2026)](https://genai.owasp.org/resource/owasp-top-10-for-agentic-applications-for-2026/) — Taxonomy of agentic-application risk categories.
|
|
815
1045
|
- [OWASP LLM Top 10 (2025)](https://owasp.org/www-project-top-10-for-large-language-model-applications/) — Taxonomy of LLM-application risk categories.
|
|
816
1046
|
- [MITRE ATLAS](https://atlas.mitre.org/) — Adversarial-threat landscape for AI systems.
|
|
817
|
-
- [
|
|
1047
|
+
- [SAF-MCP](https://github.com/secure-agentic-framework/saf-mcp) — Secure Agentic Framework for Model Context Protocol, technique catalog.
|
|
818
1048
|
- [Sigma](https://github.com/SigmaHQ/sigma) — Generic detection rule format for SIEMs (architectural precedent).
|
|
819
1049
|
- [YARA](https://github.com/VirusTotal/yara) — Pattern-matching language for malware (architectural precedent).
|
|
820
1050
|
- Five Eyes joint guidance on AI agent deployment (2026-05-01): CISA + NSA + UK NCSC + ASD + CCCS + NZ NCSC — [CyberScoop coverage](https://cyberscoop.com/cisa-nsa-five-eyes-guidance-secure-deployment-ai-agents/).
|