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.
Files changed (240) hide show
  1. package/CHANGELOG.md +688 -1
  2. package/README.md +355 -125
  3. package/dist/adapters/openshell-filter.d.ts +10 -3
  4. package/dist/adapters/openshell-filter.d.ts.map +1 -1
  5. package/dist/adapters/openshell-filter.js +10 -3
  6. package/dist/adapters/openshell-filter.js.map +1 -1
  7. package/dist/adapters/stdio-adapter.js +3 -3
  8. package/dist/adapters/stdio-adapter.js.map +1 -1
  9. package/dist/cli/mcp-tools-document.d.ts +40 -0
  10. package/dist/cli/mcp-tools-document.d.ts.map +1 -0
  11. package/dist/cli/mcp-tools-document.js +95 -0
  12. package/dist/cli/mcp-tools-document.js.map +1 -0
  13. package/dist/cli/scan-handler.d.ts +8 -0
  14. package/dist/cli/scan-handler.d.ts.map +1 -1
  15. package/dist/cli/scan-handler.js +126 -34
  16. package/dist/cli/scan-handler.js.map +1 -1
  17. package/dist/cli.d.ts.map +1 -1
  18. package/dist/cli.js +80 -43
  19. package/dist/cli.js.map +1 -1
  20. package/dist/converters/sarif.d.ts +14 -2
  21. package/dist/converters/sarif.d.ts.map +1 -1
  22. package/dist/converters/sarif.js +7 -9
  23. package/dist/converters/sarif.js.map +1 -1
  24. package/dist/corpus-event.d.ts +47 -5
  25. package/dist/corpus-event.d.ts.map +1 -1
  26. package/dist/corpus-event.js +68 -29
  27. package/dist/corpus-event.js.map +1 -1
  28. package/dist/embedding/model-loader.d.ts +2 -0
  29. package/dist/embedding/model-loader.d.ts.map +1 -1
  30. package/dist/embedding/model-loader.js +3 -1
  31. package/dist/embedding/model-loader.js.map +1 -1
  32. package/dist/enforcement.d.ts +8 -0
  33. package/dist/enforcement.d.ts.map +1 -1
  34. package/dist/enforcement.js +10 -0
  35. package/dist/enforcement.js.map +1 -1
  36. package/dist/engine.d.ts +150 -6
  37. package/dist/engine.d.ts.map +1 -1
  38. package/dist/engine.js +337 -76
  39. package/dist/engine.js.map +1 -1
  40. package/dist/eval/embedding-provenance.d.ts +40 -0
  41. package/dist/eval/embedding-provenance.d.ts.map +1 -0
  42. package/dist/eval/embedding-provenance.js +71 -0
  43. package/dist/eval/embedding-provenance.js.map +1 -0
  44. package/dist/eval/eval-harness.d.ts +34 -0
  45. package/dist/eval/eval-harness.d.ts.map +1 -1
  46. package/dist/eval/eval-harness.js +49 -2
  47. package/dist/eval/eval-harness.js.map +1 -1
  48. package/dist/eval/hackaprompt-corpus.d.ts +12 -0
  49. package/dist/eval/hackaprompt-corpus.d.ts.map +1 -1
  50. package/dist/eval/hackaprompt-corpus.js +15 -1
  51. package/dist/eval/hackaprompt-corpus.js.map +1 -1
  52. package/dist/eval/hackaprompt-provenance.d.ts +52 -0
  53. package/dist/eval/hackaprompt-provenance.d.ts.map +1 -0
  54. package/dist/eval/hackaprompt-provenance.js +108 -0
  55. package/dist/eval/hackaprompt-provenance.js.map +1 -0
  56. package/dist/eval/run-hackaprompt-benchmark.d.ts +18 -8
  57. package/dist/eval/run-hackaprompt-benchmark.d.ts.map +1 -1
  58. package/dist/eval/run-hackaprompt-benchmark.js +154 -64
  59. package/dist/eval/run-hackaprompt-benchmark.js.map +1 -1
  60. package/dist/eval/run-pint-benchmark.js +11 -1
  61. package/dist/eval/run-pint-benchmark.js.map +1 -1
  62. package/dist/eval/skill-benchmark.d.ts +26 -6
  63. package/dist/eval/skill-benchmark.d.ts.map +1 -1
  64. package/dist/eval/skill-benchmark.js +49 -16
  65. package/dist/eval/skill-benchmark.js.map +1 -1
  66. package/dist/flywheel.d.ts +4 -0
  67. package/dist/flywheel.d.ts.map +1 -1
  68. package/dist/flywheel.js +12 -4
  69. package/dist/flywheel.js.map +1 -1
  70. package/dist/hook-handler.d.ts +11 -1
  71. package/dist/hook-handler.d.ts.map +1 -1
  72. package/dist/hook-handler.js +84 -16
  73. package/dist/hook-handler.js.map +1 -1
  74. package/dist/hook-tool-output.d.ts +47 -0
  75. package/dist/hook-tool-output.d.ts.map +1 -0
  76. package/dist/hook-tool-output.js +110 -0
  77. package/dist/hook-tool-output.js.map +1 -0
  78. package/dist/index.d.ts +5 -3
  79. package/dist/index.d.ts.map +1 -1
  80. package/dist/index.js +3 -2
  81. package/dist/index.js.map +1 -1
  82. package/dist/layer-integration.d.ts +4 -2
  83. package/dist/layer-integration.d.ts.map +1 -1
  84. package/dist/layer-integration.js +6 -2
  85. package/dist/layer-integration.js.map +1 -1
  86. package/dist/mcp-server.d.ts +8 -0
  87. package/dist/mcp-server.d.ts.map +1 -1
  88. package/dist/mcp-server.js +1 -0
  89. package/dist/mcp-server.js.map +1 -1
  90. package/dist/mcp-tools/scan.d.ts.map +1 -1
  91. package/dist/mcp-tools/scan.js +9 -1
  92. package/dist/mcp-tools/scan.js.map +1 -1
  93. package/dist/measurement/enforce-lane.d.ts +66 -0
  94. package/dist/measurement/enforce-lane.d.ts.map +1 -0
  95. package/dist/measurement/enforce-lane.js +89 -0
  96. package/dist/measurement/enforce-lane.js.map +1 -0
  97. package/dist/measurement/from-eval-harness.d.ts +16 -3
  98. package/dist/measurement/from-eval-harness.d.ts.map +1 -1
  99. package/dist/measurement/from-eval-harness.js +15 -5
  100. package/dist/measurement/from-eval-harness.js.map +1 -1
  101. package/dist/measurement/in-sample-ablation.d.ts +29 -0
  102. package/dist/measurement/in-sample-ablation.d.ts.map +1 -0
  103. package/dist/measurement/in-sample-ablation.js +45 -0
  104. package/dist/measurement/in-sample-ablation.js.map +1 -0
  105. package/dist/measurement/schema.d.ts +38 -1
  106. package/dist/measurement/schema.d.ts.map +1 -1
  107. package/dist/measurement/schema.js +43 -1
  108. package/dist/measurement/schema.js.map +1 -1
  109. package/dist/quality/action-eligibility.d.ts +4 -2
  110. package/dist/quality/action-eligibility.d.ts.map +1 -1
  111. package/dist/quality/action-eligibility.js.map +1 -1
  112. package/dist/rule-confidence.d.ts +31 -0
  113. package/dist/rule-confidence.d.ts.map +1 -0
  114. package/dist/rule-confidence.js +49 -0
  115. package/dist/rule-confidence.js.map +1 -0
  116. package/dist/rule-scaffolder.d.ts.map +1 -1
  117. package/dist/rule-scaffolder.js +43 -4
  118. package/dist/rule-scaffolder.js.map +1 -1
  119. package/dist/semantic-evaluator.d.ts.map +1 -1
  120. package/dist/semantic-evaluator.js +15 -13
  121. package/dist/semantic-evaluator.js.map +1 -1
  122. package/dist/shadow-evaluator.d.ts +7 -2
  123. package/dist/shadow-evaluator.d.ts.map +1 -1
  124. package/dist/shadow-evaluator.js +29 -25
  125. package/dist/shadow-evaluator.js.map +1 -1
  126. package/dist/testcase-event.d.ts +82 -1
  127. package/dist/testcase-event.d.ts.map +1 -1
  128. package/dist/testcase-event.js +135 -16
  129. package/dist/testcase-event.js.map +1 -1
  130. package/dist/tier0-invariant.d.ts.map +1 -1
  131. package/dist/tier0-invariant.js +1 -0
  132. package/dist/tier0-invariant.js.map +1 -1
  133. package/dist/tier1-blacklist.d.ts.map +1 -1
  134. package/dist/tier1-blacklist.js +1 -0
  135. package/dist/tier1-blacklist.js.map +1 -1
  136. package/dist/tool-definition-scope.d.ts +45 -0
  137. package/dist/tool-definition-scope.d.ts.map +1 -0
  138. package/dist/tool-definition-scope.js +68 -0
  139. package/dist/tool-definition-scope.js.map +1 -0
  140. package/dist/types.d.ts +42 -2
  141. package/dist/types.d.ts.map +1 -1
  142. package/dist/verdict.d.ts +46 -2
  143. package/dist/verdict.d.ts.map +1 -1
  144. package/dist/verdict.js +99 -14
  145. package/dist/verdict.js.map +1 -1
  146. package/package.json +2 -1
  147. package/rules/agent-manipulation/ATR-2026-00030-cross-agent-attack.yaml +2 -2
  148. package/rules/agent-manipulation/ATR-2026-00139-casual-authority-redirect.yaml +1 -1
  149. package/rules/agent-manipulation/ATR-2026-00328-named-mode-persona-override.yaml +1 -1
  150. package/rules/agent-manipulation/ATR-2026-00330-yoja-allcaps-settings-block-persona.yaml +1 -1
  151. package/rules/agent-manipulation/ATR-2026-00418-weknora-mcp-config-rce.yaml +5 -5
  152. package/rules/agent-manipulation/ATR-2026-00432-superagi-output-handler-eval-rce.yaml +1 -1
  153. package/rules/agent-manipulation/ATR-2026-00440-semantic-kernel-vector-store-eval-rce.yaml +3 -3
  154. package/rules/context-exfiltration/ATR-2026-00426-nl-output-injection-credential-leak.yaml +1 -1
  155. package/rules/context-exfiltration/ATR-2026-00702-ipi-credential-exfil-via-agent-action.yaml +1 -1
  156. package/rules/context-exfiltration/ATR-2026-00707-ipi-file-exfil-with-destroy-or-tamper.yaml +1 -1
  157. package/rules/context-exfiltration/ATR-2026-00851-indirect-pi-financial-payment-exfil.yaml +1 -1
  158. package/rules/context-exfiltration/ATR-2026-01457-sysprompt-completion-clone-attack.yaml +1 -1
  159. package/rules/context-exfiltration/ATR-2026-01462-sysprompt-override-pseudo-admin.yaml +1 -1
  160. package/rules/context-exfiltration/ATR-2026-01463-imend-imsystem-prompt-injection-format.yaml +1 -1
  161. package/rules/context-exfiltration/ATR-2026-01606-ssrf-internal-network-scan.yaml +1 -1
  162. package/rules/context-exfiltration/ATR-2026-02847-policy-justified-exfil-to-email.yaml +1 -1
  163. package/rules/context-exfiltration/ATR-2026-02855-cross-email-exfil-relay.yaml +79 -0
  164. package/rules/context-exfiltration/ATR-2026-02861-exfil-send-email-with-body-directive.yaml +83 -0
  165. package/rules/context-exfiltration/ATR-2026-02866-idna-label-separator-in-fetch-url-host.yaml +104 -0
  166. package/rules/excessive-autonomy/ATR-2026-00710-ipi-physical-access-grant.yaml +1 -1
  167. package/rules/model-abuse/ATR-2026-01897-host-sabotage.yaml +2 -2
  168. package/rules/model-security/ATR-2026-00433-modelcache-torch-load-deserialization-rce.yaml +1 -1
  169. package/rules/privilege-escalation/ATR-2026-00436-enclave-vm-sandbox-escape-rce.yaml +1 -1
  170. package/rules/privilege-escalation/ATR-2026-01601-sql-injection-destructive-ddl.yaml +2 -2
  171. package/rules/privilege-escalation/ATR-2026-01612-debug-mode-privilege-escalation.yaml +1 -1
  172. package/rules/privilege-escalation/ATR-2026-02867-identifier-typed-tool-argument-dot-dot-path-segment.yaml +106 -0
  173. package/rules/prompt-injection/ATR-2026-00004-system-prompt-override.yaml +2 -2
  174. package/rules/prompt-injection/ATR-2026-00080-encoding-evasion.yaml +1 -1
  175. package/rules/prompt-injection/ATR-2026-00086-visual-spoofing.yaml +1 -1
  176. package/rules/prompt-injection/ATR-2026-00203-context-pollution-skill-description.yaml +1 -1
  177. package/rules/prompt-injection/ATR-2026-00228-structured-jailbreak.yaml +2 -2
  178. package/rules/prompt-injection/ATR-2026-00233-structured-jailbreak.yaml +2 -2
  179. package/rules/prompt-injection/ATR-2026-00256-base-n-encoding-jailbreak.yaml +1 -1
  180. package/rules/prompt-injection/ATR-2026-00264-latent-injection-translation.yaml +3 -3
  181. package/rules/prompt-injection/ATR-2026-00265-latent-injection-rag-document.yaml +1 -1
  182. package/rules/prompt-injection/ATR-2026-00282-perez-prompt-injection-hijack.yaml +4 -4
  183. package/rules/prompt-injection/ATR-2026-00321-hyphenated-system-instruction-injection.yaml +1 -1
  184. package/rules/prompt-injection/ATR-2026-00394-backspace-deletion-character-injection.yaml +2 -2
  185. package/rules/prompt-injection/ATR-2026-00446-variable-assignment-payload-injection.yaml +3 -3
  186. package/rules/prompt-injection/ATR-2026-00476-garak-web-injection-javascript-alert-1.yaml +3 -3
  187. package/rules/prompt-injection/ATR-2026-00481-garak-dan-mixedunassigned.yaml +1 -1
  188. package/rules/prompt-injection/ATR-2026-00489-garak-encoding-javascript-alert-1.yaml +3 -3
  189. package/rules/prompt-injection/ATR-2026-00508-escape-delimiter-wrapped-goal-hijacking-in-user-input-prompt.yaml +3 -3
  190. package/rules/prompt-injection/ATR-2026-00512-rules-file-backdoor-injection.yaml +1 -1
  191. package/rules/prompt-injection/ATR-2026-01005-many-shot-repetition-override.yaml +2 -2
  192. package/rules/prompt-injection/ATR-2026-01006-payload-split-string-concat-injection.yaml +2 -2
  193. package/rules/prompt-injection/ATR-2026-01015-evasion-refusal-suppression.yaml +1 -1
  194. package/rules/prompt-injection/ATR-2026-01016-evasion-response-priming-forced-opener.yaml +1 -1
  195. package/rules/prompt-injection/ATR-2026-01026-evasion-unicode-glitch-token-anomaly.yaml +2 -2
  196. package/rules/prompt-injection/ATR-2026-01304-indirect-injection-carrier-important-override.yaml +1 -1
  197. package/rules/prompt-injection/ATR-2026-01759-dos-new-important-instructions-injection-in-document.yaml +1 -1
  198. package/rules/prompt-injection/ATR-2026-01865-llmail-fake-email-boundary-marker.yaml +1 -1
  199. package/rules/prompt-injection/ATR-2026-02010-emoji-only-payload.yaml +2 -2
  200. package/rules/prompt-injection/ATR-2026-02815-injected-halt-order-canned-reply-dos.yaml +80 -0
  201. package/rules/prompt-injection/ATR-2026-02820-tool-result-orders-agent-to-hide-its-own-action.yaml +106 -0
  202. package/rules/prompt-injection/ATR-2026-02858-context-suppression-directive.yaml +73 -0
  203. package/rules/prompt-injection/ATR-2026-02859-tool-output-agent-role-reassignment.yaml +71 -0
  204. package/rules/prompt-injection/ATR-2026-02860-forged-instruction-boundary-marker.yaml +70 -0
  205. package/rules/prompt-injection/ATR-2026-02862-fake-chat-template-turn-injection.yaml +79 -0
  206. package/rules/skill-compromise/ATR-2026-00060-skill-impersonation.yaml +1 -1
  207. package/rules/skill-compromise/ATR-2026-00063-skill-chain-attack.yaml +2 -2
  208. package/rules/skill-compromise/ATR-2026-00066-parameter-injection.yaml +2 -2
  209. package/rules/skill-compromise/ATR-2026-00149-skill-exfil-compound.yaml +6 -6
  210. package/rules/skill-compromise/ATR-2026-00223-reverse-shell-dropper.yaml +2 -2
  211. package/rules/skill-compromise/ATR-2026-01755-backdoor-pot-linguistic-trigger-phrase.yaml +1 -1
  212. package/rules/skill-compromise/ATR-2026-01756-backdoor-pot-symbol-emoticon-trigger.yaml +1 -1
  213. package/rules/skill-compromise/ATR-2026-02261-code-credential-exfil-chain.yaml +1 -1
  214. package/rules/tool-poisoning/ATR-2026-00012-unauthorized-tool-call.yaml +23 -23
  215. package/rules/tool-poisoning/ATR-2026-00013-tool-ssrf.yaml +16 -5
  216. package/rules/tool-poisoning/ATR-2026-00161-important-tag-cross-tool-shadowing.yaml +1 -1
  217. package/rules/tool-poisoning/ATR-2026-00277-echo-template-command-injection.yaml +2 -2
  218. package/rules/tool-poisoning/ATR-2026-00494-garak-exploitation-mixedunassigned.yaml +4 -4
  219. package/rules/tool-poisoning/ATR-2026-00581-mcp-tool-rug-pull-post-approval-redefinition.yaml +1 -1
  220. package/rules/tool-poisoning/ATR-2026-01303-tool-schema-enumeration-social-engineering.yaml +1 -1
  221. package/rules/tool-poisoning/ATR-2026-01307-mcp-dns-rebinding-attack.yaml +2 -2
  222. package/rules/tool-poisoning/ATR-2026-01775-semantic-mcp-tool-manifest-poisoning.yaml +1 -1
  223. package/rules/tool-poisoning/ATR-2026-01932-shadow-undeclared-mcp-server-registration.yaml +1 -1
  224. package/rules/tool-poisoning/ATR-2026-02025-mcp-full-schema-poisoning-nondescription-field.yaml +1 -1
  225. package/rules/tool-poisoning/ATR-2026-02817-untrusted-content-dictates-tool-arguments.yaml +83 -0
  226. package/rules/tool-poisoning/ATR-2026-02864-non-canonical-ipv4-host-in-url-tool-argument.yaml +102 -0
  227. package/rules/tool-poisoning/ATR-2026-02865-read-only-utility-write-flag-in-command-argument.yaml +157 -0
  228. package/rules/tool-poisoning/ATR-2026-02868-ssrf-ipv6-transition-address-embedded-private-ipv4.yaml +107 -0
  229. package/spec/README.md +6 -3
  230. package/spec/atr-event-v1.0.md +13 -8
  231. package/spec/atr-method-v1.1.md +2 -2
  232. package/spec/category-registry/gemara/README.md +102 -0
  233. package/spec/category-registry/gemara/ai-agent-capability-catalog.yaml +157 -0
  234. package/spec/category-registry/gemara/atr-attack-vector-catalog.yaml +130 -0
  235. package/spec/category-registry/gemara/atr-detection-control-catalog.yaml +327 -0
  236. package/spec/category-registry/gemara/atr-threat-catalog.yaml +246 -0
  237. package/spec/category-registry/gemara/src/editorial.yaml +743 -0
  238. package/spec/mappings/README.md +1 -1
  239. package/spec/mappings/atr-to-nist-csf-2.0.md +5 -4
  240. package/spec/schema/event.schema.json +1 -1
@@ -0,0 +1,83 @@
1
+ title: Injected Directive to Send Email with Attacker-Specified Body
2
+ id: ATR-2026-02861
3
+ rule_version: 1
4
+ status: experimental
5
+ description: |
6
+ Detects a directive inside tool-returned content (a fetched email, document, web page or other tool output) that tells the agent to send an email, mail, message or notification to a recipient "with [the] body" of the attacker's choosing: the core action of mail-based exfiltration through indirect prompt injection. The condition reads only the tool response, so a user who asks their own agent to send such an email does not trigger it. Scope is narrow and the evidence comes from one benchmark: the rule was mined from LLMail-Inject, where it matches 214 of 1,973 attack submissions (10.8%) and adds coverage for submissions no other rule matched in the tool-response shape; it matches none of the other attack corpora in the repository, including browsesafe-bench. The benign corpora contain very little text with this phrasing (about 33 samples carry the "send an email/mail/message/notification to" prefix), so its 0 false positives there are a weak measurement. It complements ATR-2026-01862, which keys on the recipient address used by that benchmark rather than on the grammar of the directive.
7
+ author: ATR Community (via LLMail-Inject benchmark)
8
+ date: 2026/10/15
9
+ schema_version: '0.1'
10
+ detection_tier: pattern
11
+ maturity: test
12
+ severity: high
13
+ references:
14
+ owasp_llm:
15
+ - LLM01:2025
16
+ - LLM02:2025
17
+ owasp_agentic:
18
+ - ASI01:2026
19
+ - ASI02:2026
20
+ mitre_atlas:
21
+ - AML.T0051.001 - Indirect
22
+ - AML.T0057 - LLM Data Leakage
23
+ mitre_attack:
24
+ - T1567 - Exfiltration Over Web Service
25
+ research:
26
+ - https://github.com/microsoft/llmail-inject-challenge
27
+ compliance:
28
+ eu_ai_act:
29
+ - article: '15'
30
+ context: Article 15 (accuracy, robustness and cybersecurity) calls for resilience against attempts to alter an AI system's use or behaviour by exploiting its vulnerabilities; this rule provides detection evidence supporting that requirement for injected directives that steer an agent into mailing data to an attacker-chosen recipient.
31
+ strength: primary
32
+ - article: '10'
33
+ context: Article 10 (data and data governance) requires control over the data an AI system processes; this rule provides detection evidence for a context-exfiltration attempt (injected send-email-with-body directive) affecting that data.
34
+ strength: secondary
35
+ nist_ai_rmf:
36
+ - subcategory: MS.2.7
37
+ context: NIST AI RMF MEASURE 2.7 (security and resilience evaluated and documented) is supported by this rule's runtime detection of injected send-email-with-body directives in tool output.
38
+ strength: primary
39
+ - subcategory: MS.2.10
40
+ context: NIST AI RMF MEASURE 2.10 (privacy risk examined and documented) is supported by this rule's detection of attempts to exfiltrate conversation or retrieved data by email.
41
+ strength: secondary
42
+ iso_42001:
43
+ - clause: '8.1'
44
+ context: 'Clause 8.1 (operational planning and control): runtime detection of injected exfiltration directives in tool output is an operational control on how the agent acts on retrieved content.'
45
+ strength: primary
46
+ - clause: '6.2'
47
+ context: 'Clause 6.2 (AI objectives and planning to achieve them): detections from this rule give measurable input to objectives for preventing data exfiltration through indirect prompt injection.'
48
+ strength: secondary
49
+ tags:
50
+ category: context-exfiltration
51
+ subcategory: exfil-send-email-with-body-directive
52
+ scan_target: mcp
53
+ confidence: high
54
+ agent_source:
55
+ type: mcp_exchange
56
+ framework:
57
+ - openai
58
+ - anthropic
59
+ - langchain
60
+ - llamaindex
61
+ - autogen
62
+ - crewai
63
+ provider:
64
+ - any
65
+ detection:
66
+ conditions:
67
+ - field: tool_response
68
+ operator: regex
69
+ value: (?i)\bsend\s+(?:an?\s+)?(?:e-?mail|mail|message|notification)\s+to\s+[\s\S]{0,60}?\bwith\s+(?:the\s+)?body\b
70
+ description: Directive in tool output to send an email/mail/message/notification to a recipient with a specified body
71
+ condition: any
72
+ false_positives:
73
+ - Tool output that legitimately relays a person's own request, such as a ticketing or CRM system echoing "send an email to the customer with the body below"
74
+ - API or integration documentation returned by a tool that describes sending a message or notification to a channel or user "with the body" field set to some value
75
+ - Security documentation that quotes a mail-exfiltration payload verbatim
76
+ response:
77
+ actions:
78
+ - alert
79
+ - snapshot
80
+ - escalate
81
+ auto_response_threshold: high
82
+ message_template: '[ATR-2026-02861] Injected Directive to Send Email with Attacker-Specified Body detected.'
83
+ confidence: 85
@@ -0,0 +1,104 @@
1
+ title: Non-ASCII IDNA Label Separator Inside the Host of a Fetch-Tool URL Argument
2
+ id: ATR-2026-02866
3
+ rule_version: 1
4
+ status: experimental
5
+ description: |
6
+ Detects a tool call whose URL-typed argument (url, uri, target_url, href, link, src, endpoint, location, website, site, page, target) or host-typed argument (host, hostname, domain, *_host, server_name) carries one of five separator characters: the three that IDNA / UTS #46 mapping turns into an ordinary dot -- U+3002 IDEOGRAPHIC FULL STOP, U+FF0E FULLWIDTH FULL STOP, U+FF61 HALFWIDTH IDEOGRAPHIC FULL STOP -- plus the two look-alike separators U+2024 ONE DOT LEADER and U+FE52 SMALL FULL STOP, INSIDE THE HOST COMPONENT (after '//' and before the first '/', '?' or '#'), and immediately followed by another hostname label, a path/query/fragment delimiter, or a ':port'. Examples: https://evil。com/page, https://evil.com./page, https://internal-admin。corp。example/api/keys.
7
+ Mined from CVE-2026-107288 (Pydantic AI web_fetch_tool and the WebFetch local fallback, 1.77.0 up to 1.107.6 / 2.44.0): blocked_domains entries were compared with the URL hostname before either side was normalised to the form getaddrinfo resolves, so a model steered by injected content could spell a blocked host with a non-ASCII label separator and the application fetched it with its own privileges (SSRF). The detection is not bound to any domain: a hostname has no legitimate reason to carry these characters in the serialized tool argument, because every conforming client folds them to '.' before resolution, so their presence is the signature of a string-level allow/block-list being dodged. The same shape defeats any agent fetch tool whose domain filter compares strings before IDNA mapping.
8
+ BOTH ENCODINGS. The separator is matched as the literal character (what JSON.stringify emits) and as the JSON escape \u3002 / \uff0e / \uff61 / \u2024 / \ufe52 (what Python json.dumps emits with its default ensure_ascii=True), so a Python-side hook log is covered as well.
9
+ WHY A KEYED ARGUMENT IS REQUIRED. Chinese and Japanese prose routinely ends a sentence with U+3002 directly after a URL ("請參考 https://example.com。謝謝"), and mixed-language text can put an ASCII word straight after that full stop ("https://example.com。GitHub 上也有說明"). The second form is indistinguishable by pattern from https://evil。com, so the rule only reads a value that sits behind a quoted URL/host argument key, where prose does not appear. A separator that is the LAST character of the value (the trailing full stop an extractor copies from a sentence) is also excluded.
10
+ HOST-TYPED ARGUMENTS ARE READ STRICTLY. Keys such as domain, host or server_name are also used for free text (a topic domain, a podcast host, a display name), so for those keys the WHOLE value must be ASCII hostname shaped -- [a-z0-9.-] labels, the separator, more labels, an optional ':port' -- and must run to the closing quote. CJK prose in such a field (醫療。AI 應用, 王小明。Guest: Amy, 東京サーバー。Tokyo-1) is therefore not read.
11
+ SCOPE AND LIMITS, stated honestly. (1) Not covered: case variation (EVIL.COM) and a plain trailing root dot (evil.com.) -- they are the same bytes as ordinary URLs. (2) Not covered by this rule: fullwidth-letter hostnames with only ASCII dots (evil.com) -- ATR-2026-00444 sees those; cloud-metadata hosts written with separators also hit ATR-2026-00013. (3) Not covered: a bare URL in prose or in a non-URL argument (a chat message, a document body, a search query); that form is undecidable from Chinese punctuation. A URL passed under a key outside the lists above (q, query, text, content, input) is a known gap. (4) Not covered: punycode (xn--) spellings of a blocked IDN, percent-encoded host bytes, and a trailing separator that ends the value. (5) A security test suite or advisory that reproduces the serialized call verbatim will match.
12
+ RE2 PORTABILITY. Both conditions are written for RE2-family engines (Go regexp, Rust regex) as well as JavaScript and Python re: the five separator characters and the fullwidth letter/digit ranges are written as literal characters rather than \\uXXXX escapes (which RE2 spells \\x{XXXX} and JS without the u flag does not), there is no lookahead or lookbehind, and every repeat bound is at most 253. The "not the last character of the value" exclusion is expressed by requiring a following label character, delimiter or ':port' after the separator instead of a negative lookahead, so the matched behaviour is unchanged.
13
+ author: ATR Community (CVE sync)
14
+ date: 2026/10/22
15
+ schema_version: '0.1'
16
+ detection_tier: pattern
17
+ maturity: test
18
+ severity: medium
19
+ references:
20
+ cve:
21
+ - CVE-2026-107288
22
+ cwe:
23
+ - CWE-918
24
+ - CWE-1289
25
+ - CWE-176
26
+ owasp_llm:
27
+ - LLM02:2025
28
+ - LLM06:2025
29
+ owasp_agentic:
30
+ - ASI02:2026
31
+ mitre_atlas:
32
+ - AML.T0053 - AI Agent Tool Invocation
33
+ mitre_attack:
34
+ - T1090 - Proxy
35
+ external:
36
+ - https://nvd.nist.gov/vuln/detail/CVE-2026-107288
37
+ - https://github.com/pydantic/pydantic-ai/commit/a9dab92099d0ef9d5d4aa34ccac8a6f1b0e51284
38
+ - https://github.com/pydantic/pydantic-ai/commit/c1f212a084cbfa0012f2044cdb4731d214b3b983
39
+ - https://github.com/pydantic/pydantic-ai/commit/490335f8e2322e143a79337ddca9410e0176c812
40
+ - https://github.com/pydantic/pydantic-ai/releases/tag/v1.107.6
41
+ - https://www.unicode.org/reports/tr46/
42
+ metadata_provenance:
43
+ cve: human-reviewed
44
+ cwe: human-reviewed
45
+ owasp_llm: human-reviewed
46
+ owasp_agentic: human-reviewed
47
+ mitre_atlas: human-reviewed
48
+ mitre_attack: human-reviewed
49
+ compliance:
50
+ eu_ai_act:
51
+ - article: '15'
52
+ context: Article 15 (accuracy, robustness and cybersecurity) calls for resilience against attempts to circumvent security controls. This rule provides detection evidence supporting that requirement by flagging a fetch-tool URL whose host is spelled with an IDNA label separator so that a string-compared domain block list is bypassed.
53
+ strength: primary
54
+ - article: '10'
55
+ context: Article 10 (data and data governance) concerns which data an AI system draws on. An SSRF fetch of a blocked internal host pulls unauthorised data into the agent's context; this rule provides detection evidence supporting control over that data path.
56
+ strength: secondary
57
+ nist_ai_rmf:
58
+ - subcategory: MS.2.7
59
+ context: MS.2.7 requires security and resilience of the AI system to be evaluated. Counting tool calls whose URL host carries a non-ASCII label separator measures whether the fetch tool's domain control actually holds against normalisation-based bypass.
60
+ strength: primary
61
+ - subcategory: MS.2.10
62
+ context: MS.2.10 covers privacy risk. A blocked internal or metadata host reached through SSRF can expose credentials and personal data to the model; this rule surfaces the attempt for that assessment.
63
+ strength: secondary
64
+ iso_42001:
65
+ - clause: '8.1'
66
+ context: 'ISO/IEC 42001 Clause 8.1 (operational planning and control): the fetch tool''s domain block list is an operational control, and this rule reports arguments crafted to slip past it before IDNA normalisation.'
67
+ strength: primary
68
+ - clause: '6.2'
69
+ context: 'ISO/IEC 42001 Clause 6.2 (AI objectives and planning): keeping agent egress inside approved destinations is a security objective, and this rule supplies runtime evidence of attempts to defeat it.'
70
+ strength: secondary
71
+ tags:
72
+ category: context-exfiltration
73
+ subcategory: ssrf-idna-label-separator-host
74
+ scan_target: runtime
75
+ confidence: high
76
+ source: cve-disclosure
77
+ agent_source:
78
+ type: tool_call
79
+ framework:
80
+ - any
81
+ provider:
82
+ - any
83
+ detection:
84
+ condition: any
85
+ conditions:
86
+ - field: tool_args
87
+ operator: regex
88
+ value: \\?["\x27](?:[a-z]{0,16}_?ur[il]|href|link|src|endpoint|location|website|site|page|target)\\?["\x27]\s{0,3}[:=]\s{0,3}\\?["\x27]\s{0,3}(?:[a-z][a-z0-9+.-]{0,15}:)?//[^\s/?#"\x27\\。.。․﹒]{0,253}(?:[。.。․﹒]|\\u(?:3002|ff0e|ff61|2024|fe52))(?:[a-z0-9-]|[0-9A-Za-z]|[/?#]|:\d)
89
+ description: A quoted URL-typed argument whose HOST component (between '//' and the first '/', '?' or '#') contains an IDNA label separator (U+3002, U+FF0E, U+FF61) or look-alike dot (U+2024, U+FE52), literal or JSON-escaped, followed by another label, a delimiter or a port -- the CVE-2026-107288 blocked_domains bypass shape.
90
+ - field: tool_args
91
+ operator: regex
92
+ value: \\?["\x27](?:host|hostname|domain|[a-z]{1,12}_host|server_name)\\?["\x27]\s{0,3}[:=]\s{0,3}\\?["\x27]\s{0,3}[a-z0-9.-]{1,253}(?:[。.。․﹒]|\\u(?:3002|ff0e|ff61|2024|fe52))[a-z0-9-](?:[a-z0-9.-]|[。.。․﹒]|\\u(?:3002|ff0e|ff61|2024|fe52)){0,253}(?::\d{1,5})?\\?["\x27]
93
+ description: The same separator inside a bare host-typed argument (host / hostname / domain / *_host / server_name) that a tool resolves directly -- the scheme-less form of the same normalisation bypass. The whole value must be an ASCII hostname (labels, separators, optional :port) running to the closing quote, so CJK free text in such a field is not read.
94
+ false_positives:
95
+ - Security test suites, CVE reproductions and advisories that quote the serialized tool call verbatim (for example the upstream tests/test_ssrf.py fixtures) match -- same bytes as the attack.
96
+ - A URL argument whose host was copied out of East Asian text together with a full stop AND has more host text after it (https://example.com。cn/...) matches. That value does not resolve as written by a strict parser and does resolve to a different host after IDNA folding, so it is reported deliberately.
97
+ - A link / href / url field populated from scraped prose can carry a sentence-final full stop followed by an ASCII word, for example {"link":"https://t.co。Thanks"}. That value matches, because it is byte-for-byte the same shape as https://evil。com and cannot be told apart by pattern.
98
+ - 'Not matched by design: a separator in the PATH, QUERY or FRAGMENT (https://zh.wikipedia.org/wiki/句號。, ?q=台北。天氣), a separator that is the last character of the value, punycode xn-- hosts, native IDN hosts such as bücher.example, and any URL that appears in prose or a non-URL argument.'
99
+ response:
100
+ actions:
101
+ - alert
102
+ message_template: |
103
+ [ATR-2026-02866] A fetch-tool URL or host argument spells its hostname with a non-ASCII label separator (U+3002 / U+FF0E / U+FF61 / U+2024 / U+FE52). DNS resolution folds these to '.', so a string-compared domain block list can be bypassed (CVE-2026-107288). Normalise the host with IDNA/UTS #46 before any allow/block-list check and re-evaluate this call.
104
+ confidence: 78
@@ -63,7 +63,7 @@ detection:
63
63
  description: Unlock door to allow entry for a third party
64
64
  - field: content
65
65
  operator: regex
66
- value: (?i)(?:grant|add|give)\s+(?:permanent|temporary|guest|unlimited)?\s+access\s+to\s+(?:my\s+)?(?:friend|guest|person|user|visitor|Amy|Bob|Alice)[^.\n]{0,80}(?:smart\s+lock|August|Kwikset|home|premises|house|building)
66
+ value: (?i)(?:grant|add|give)\s(?:\s*(?:permanent|temporary|guest|unlimited))?\s+access\s+to\s+(?:my\s+)?(?:friend|guest|person|user|visitor|Amy|Bob|Alice)[^.\n]{0,80}(?:smart\s+lock|August|Kwikset|home|premises|house|building)
67
67
  description: Grant person access to home/premises via smart lock
68
68
  - field: content
69
69
  operator: regex
@@ -69,7 +69,7 @@ detection:
69
69
  description: 'BIPIA host-sabotage invariant #2'
70
70
  - field: user_input
71
71
  operator: regex
72
- value: (?i)while\s+True\s*:\s*\n?\s*os\.fork\(\)
72
+ value: (?i)while\s+True\s*:\s*os\.fork\(\)
73
73
  description: 'BIPIA host-sabotage invariant #3'
74
74
  - field: user_input
75
75
  operator: regex
@@ -81,7 +81,7 @@ detection:
81
81
  description: 'BIPIA host-sabotage invariant #5'
82
82
  - field: user_input
83
83
  operator: regex
84
- value: (?i)while\s+True\s*:\s*\n?\s*create_window\(\)
84
+ value: (?i)while\s+True\s*:\s*create_window\(\)
85
85
  description: 'BIPIA host-sabotage invariant #6'
86
86
  condition: any
87
87
  false_positives:
@@ -81,7 +81,7 @@ detection:
81
81
  conditions:
82
82
  - field: content
83
83
  operator: regex
84
- value: (?i)torch\.load\s*\(\s*[^,)]*(?:request\.|flask\.request|user_input|untrusted|attacker|payload|upload|f\.read\(\)|response\.content)[^)]{0,200}\)
84
+ value: (?i)torch\.load\s*\([^,)]*(?:request\.|flask\.request|user_input|untrusted|attacker|payload|upload|f\.read\(\)|response\.content)[^)]{0,200}\)
85
85
  description: torch.load called on attacker-derived input — direct CVE-2025-45146 sink
86
86
  - field: content
87
87
  operator: regex
@@ -8,7 +8,7 @@ author: ATR Community
8
8
  date: 2026/05/10
9
9
  schema_version: '0.1'
10
10
  detection_tier: pattern
11
- maturity: stable
11
+ maturity: test
12
12
  severity: critical
13
13
  references:
14
14
  owasp_llm:
@@ -60,11 +60,11 @@ detection:
60
60
  conditions:
61
61
  - field: tool_args
62
62
  operator: regex
63
- value: (?i)(?:';|"\s*;|--\s*)\s*(?:DROP\s+(?:TABLE|DATABASE|INDEX|VIEW)|TRUNCATE\s+(?:TABLE\s+)?\w|DELETE\s+FROM\s+\w)
63
+ value: (?i)(?:';|"\s*;|--)\s*(?:DROP\s+(?:TABLE|DATABASE|INDEX|VIEW)|TRUNCATE\s+(?:TABLE\s+)?\w|DELETE\s+FROM\s+\w)
64
64
  description: 'SQL injection: quote-termination followed by destructive DDL'
65
65
  - field: tool_args
66
66
  operator: regex
67
- value: (?i)\bDROP\s+TABLE\s+\w+\s*;?\s*--
67
+ value: (?i)\bDROP\s+TABLE\s+\w+\s*(?:;\s*)?--
68
68
  description: DROP TABLE with comment suppressor
69
69
  - field: user_input
70
70
  operator: regex
@@ -69,7 +69,7 @@ detection:
69
69
  description: Explicit privileged/debug/admin mode activation command targeting the agent (enter/switch to/go into)
70
70
  - field: user_input
71
71
  operator: regex
72
- value: (?i)(?:^|\n)\s*(?:/debug|/admin|/system|/root)(?![\w/])
72
+ value: (?i)(?:^|\n)[^\S\n]*(?:/debug|/admin|/system|/root)(?![\w/])
73
73
  description: Slash-command debug/admin invocation as the leading token of a line (not a URL/config path)
74
74
  - field: user_input
75
75
  operator: regex
@@ -0,0 +1,106 @@
1
+ title: Dot-Dot Path Segment Inside an Identifier-Typed Tool Argument (REST-Wrapper Path Traversal)
2
+ id: ATR-2026-02867
3
+ rule_version: 1
4
+ status: experimental
5
+ description: |
6
+ Detects a tool-call argument whose KEY says it is an opaque identifier (product_number, licensee_number, customer_id, order_no, user_uuid, productNumber, productId, ...) but whose VALUE carries a dot-dot path segment: a '..' (or %2e%2e, .%2e, %2e.) that starts the value or follows a separator, and is itself followed by a separator ('/', '\', %2f, %5c) or by the end of the value.
7
+ This is the shape of CVE-2026-57496 / GHSA-hxpf-9xvq-wph8 in the NetLicensing MCP Server (< 0.1.8): netlicensing_get_product interpolated the caller-controlled product_number into the REST path /product/{product_number}. A single product_number of "../token" is normalised by httpx from /product/../token to /token, the response is serialised through the ordinary wrapper instead of the token-redacting one, and the raw API token is returned to the agent. The fix (commit b8fd0ea) added a path-segment validator that rejects '..', '..%2f', '%2e%2e/', backslashes and encoded separators.
8
+ The rule is deliberately not vendor-scoped. Any MCP server that wraps a REST API by formatting identifier arguments into a URL path has the same bug class, and an identifier never legitimately contains a dot-dot path segment. It keys on the identifier-typed argument name rather than on the tool name or on the '/token' target, so it also fires on licensee_number, a camelCase productNumber, a bare '..' (which walks to the API root) or an encoded separator.
9
+ Why a new rule rather than relying on existing ones (measured 2026-10-22 on origin/main 69f7f2809 with tool_call and mcp_exchange events whose tool_args is the JSON-encoded argument object): the GHSA PoC {"product_number":"../token"}, "%2e%2e/token", "..\\token" and {"licensee_number":"../token"} matched no rule. ATR-2026-01948 targets this exact CVE but its key regexes expect product_number to be followed directly by ':' or '=', so the closing JSON quote of a real tool_args key defeats it; ATR-2026-02251 / 02353 have the same key-quote gap and list only *_id fields. ATR-2026-00569 catches only the '..%2f' encoding and ATR-2026-00066 / 01616 need two or more '../' levels, while one level is enough against a REST path.
10
+ Related rule: ATR-2026-01948 (context-exfiltration) is the vendor-specific rule for this same CVE. This rule is the generalised identifier-argument form; keep the two cross-referenced when either is merged, narrowed or retired.
11
+ Scope and limits. Only JSON double-quoted keys are read ("key": "value"), so a JSON-escaped snippet quoted inside another argument (an agent writing an advisory) does not match. Path-typed keys (path, file, dir, url, key, object_key) are intentionally out of scope - they are covered by the file-path traversal rules - so a traversal smuggled through a key with a non-identifier name (sku, name, product) is not detected here. *_code keys are also out of scope: source_code / python_code / shell_code usually hold free-form program text in which '/../' is ordinary, so product_code / promo_code identifiers are an accepted gap. Plural keys (product_numbers) and array values are not read, and a Tomcat-style path parameter ('..;/token') is not in the separator set. Keys that only END in "id" are matched case-insensitively, so a non-identifier key such as "valid" or "android" holding a dot-dot segment would also match, and identifier keys that legitimately carry a relative path (model_id, doc_id, folder_id) will match as well. CWE-22, CWE-23.
12
+ author: ATR Community (CVE sync)
13
+ date: 2026/10/22
14
+ schema_version: '0.1'
15
+ detection_tier: pattern
16
+ maturity: test
17
+ severity: high
18
+ references:
19
+ cve:
20
+ - CVE-2026-57496
21
+ ghsa:
22
+ - GHSA-hxpf-9xvq-wph8
23
+ cwe:
24
+ - CWE-22
25
+ - CWE-23
26
+ owasp_llm:
27
+ - LLM06:2025
28
+ owasp_agentic:
29
+ - ASI03:2026
30
+ - ASI02:2026
31
+ mitre_atlas:
32
+ - AML.T0053 - AI Agent Tool Invocation
33
+ - AML.T0055 - Unsecured Credentials
34
+ mitre_attack:
35
+ - T1552 - Unsecured Credentials
36
+ external:
37
+ - https://github.com/Labs64/NetLicensing-MCP/security/advisories/GHSA-hxpf-9xvq-wph8
38
+ - https://github.com/Labs64/NetLicensing-MCP/commit/b8fd0ea76d533202573eb24add9fb2fbd9331496
39
+ - https://nvd.nist.gov/vuln/detail/CVE-2026-57496
40
+ metadata_provenance:
41
+ cve: human-reviewed
42
+ cwe: human-reviewed
43
+ owasp_llm: human-reviewed
44
+ owasp_agentic: human-reviewed
45
+ mitre_atlas: human-reviewed
46
+ mitre_attack: human-reviewed
47
+ compliance:
48
+ eu_ai_act:
49
+ - article: '15'
50
+ context: Article 15 (accuracy, robustness and cybersecurity) requires resilience against attempts to exploit system vulnerabilities; this rule provides detection evidence supporting that requirement by flagging an identifier argument that steers an MCP server's REST request onto an unintended endpoint such as /token.
51
+ strength: primary
52
+ - article: '14'
53
+ context: Article 14 (human oversight) needs operators to be able to see and interrupt anomalous agent actions; an alert on a traversal-bearing identifier argument provides detection evidence supporting oversight of tool calls that would otherwise silently return credentials to the model.
54
+ strength: secondary
55
+ nist_ai_rmf:
56
+ - subcategory: MS.2.7
57
+ context: MEASURE 2.7 requires AI system security and resilience to be evaluated; inspecting identifier-typed tool arguments for dot-dot path segments is a per-invocation measurement of the agent-to-tool boundary rather than an assumption that each MCP server validates its own path segments.
58
+ strength: primary
59
+ - subcategory: MG.2.3
60
+ context: MANAGE 2.3 requires procedures to respond to and recover from identified AI risks; this rule is the runtime trigger for responding to a privilege-escalating path traversal through an agent tool argument.
61
+ strength: secondary
62
+ iso_42001:
63
+ - clause: '8.1'
64
+ context: Clause 8.1 operational planning and control covers externally provided processes such as third-party MCP servers; this rule is an operational control applied to each tool invocation independent of the server's own input validation.
65
+ strength: primary
66
+ - clause: '6.2'
67
+ context: Clause 6.2 AI objectives and planning to achieve them include keeping credentials out of model context; detecting the traversal that reroutes a lookup onto a token endpoint supports that objective.
68
+ strength: secondary
69
+ tags:
70
+ category: privilege-escalation
71
+ subcategory: identifier-argument-path-traversal
72
+ scan_target: tool_args
73
+ confidence: medium
74
+ source: cve-disclosure
75
+ vendor_sources: netlicensing-mcp-cve-2026-57496
76
+ suppress_in_code_blocks: true
77
+ agent_source:
78
+ type: tool_call
79
+ framework:
80
+ - mcp
81
+ - any
82
+ provider:
83
+ - any
84
+ detection:
85
+ condition: any
86
+ method: pattern
87
+ false_positives:
88
+ - 'A tool whose API genuinely uses ''..'' as an identifier, for example a filesystem-browser tool that addresses the parent entry as {"entry_id": ".."}. Such an argument is itself a traversal and will match.'
89
+ - Security test fixtures and CVE reproductions that pass the traversal payload through a real tool call match by design.
90
+ - Keys that end in 'id' are matched case-insensitively (the engine compiles this condition format with flag 'i'), so a non-identifier key such as 'valid' or 'android' holding a dot-dot segment would also match.
91
+ - 'Identifier-named keys that legitimately hold a relative filesystem path will match: a Hugging Face from_pretrained-style local checkpoint {"model_id": "../checkpoints/llama-ft"}, a RAG or document tool that uses the file path as the document id {"doc_id": "docs/../README.md"}, or a folder-navigation tool addressing the parent folder {"folder_id": ".."}. These are indistinguishable from the traversal by value alone; suppress per tool when the target server resolves such ids against a sandboxed root.'
92
+ conditions:
93
+ - field: tool_args
94
+ operator: regex
95
+ value: '"(?:[a-z0-9_-]{0,40}[_-](?:id|number|num|no|nr|uuid|guid|slug)|[a-z0-9]{1,40}(?:number|uuid|guid|id)|id|number|uuid|guid|slug)"\s{0,3}:\s{0,3}"(?:[^"\n]{0,120}?(?:/|\\|%2f|%5c))?(?:\.\.|%2e%2e|\.%2e|%2e\.|%252e%252e)(?:/|\\|%2f|%5c|%252f|%255c|")'
96
+ description: An identifier-typed JSON argument (snake_case *_id/*_number/*_no/*_uuid/*_slug, camelCase *Number/*Id/*Uuid, or a bare id/number key; *_code keys excluded because they usually carry program text) whose value contains a dot-dot path segment - at the start of the value or after a separator, followed by a separator or the end of the value - literal or percent-encoded
97
+ response:
98
+ actions:
99
+ - alert
100
+ - snapshot
101
+ actions_rationale: 'response-action eligibility (docs/RESPONSE-ACTION-ELIGIBILITY.md): new CVE-derived candidate without a benign-corpus FP measurement beyond the CI gate; ceiling = observe.'
102
+ notify:
103
+ - security_team
104
+ message_template: |
105
+ [ATR-2026-02867] HIGH: an identifier-typed tool argument contains a dot-dot path segment. Opaque IDs never contain '..'; when an MCP server formats the ID into a REST path, the segment is normalised away and the request lands on a different endpoint (CVE-2026-57496: product_number "../token" reached /token and leaked the API token). Check whether the target server validates path segments before building URLs.
106
+ confidence: 72
@@ -90,7 +90,7 @@ detection:
90
90
  description: Imperative verbs targeting system prompt/instructions change (requires 'system' as part of the phrase)
91
91
  - field: user_input
92
92
  operator: regex
93
- value: (?i)(?:\{\s*["']?role["']?\s*:\s*["']?system["']?\s*[,}]?[\s\S]{0,160}?(?:ignore\b|disregard\b|override\b|bypass\b|disable\b|unrestricted\b|jailb?reak\b|without\s+(?:restrictions?|filters?|safety|limits?)|no\s+(?:safety|restrictions?|filters?|guidelines?)|new\s+instructions?\b)|\{\s*["']?(?:system_prompt|system_message|system_instruction|system_content)["']?\s*:\s*["']?)
93
+ value: (?i)(?:\{\s*["']?role["']?\s*:\s*["']?system["']?\s*(?:[,}][\s\S]{0,160}?|(?:\S[\s\S]{0,159}?)?)(?:ignore\b|disregard\b|override\b|bypass\b|disable\b|unrestricted\b|jailb?reak\b|without\s+(?:restrictions?|filters?|safety|limits?)|no\s+(?:safety|restrictions?|filters?|guidelines?)|new\s+instructions?\b)|\{\s*["']?(?:system_prompt|system_message|system_instruction|system_content)["']?\s*:\s*["']?)
94
94
  description: JSON-formatted system role injection (v2 — a bare role-key opener is the standard chat-completions message shape and appeared in 11 benign LLM-integration skills. The role branch now requires the value to actually be system AND an override phrase within the same message object, which is what separates an injected system turn from an ordinary API example; the explicit system_prompt / system_message keys still fire alone. The system-role true_positive is unaffected because its content carries an override phrase. Dropped the bare persona / identity / character keys, which carry no override semantics on their own)
95
95
  - field: user_input
96
96
  operator: regex
@@ -118,7 +118,7 @@ detection:
118
118
  description: Configuration object injection that disables a safety control (v2 — the old form matched any config object containing a 'system'/'role'/'instructions' key, which is the shape of every legitimate LLM SDK call and FP'd on benign skills passing systemInstruction to a provider config. It now requires a safety-control key assigned a disabling value, which is the actual attack; no true_positive relied on the broad form)
119
119
  - field: user_input
120
120
  operator: regex
121
- value: (?i)(---+|===+|\*\*\*+|~~~+)\s*(system|instruction|override|admin|configuration|new\s+prompt)\s*(---+|===+|\*\*\*+|~~~+)
121
+ value: (?i)(---|===|\*\*\*|~~~)\s*(system|instruction|override|admin|configuration|new\s+prompt)\s*(---|===|\*\*\*|~~~)
122
122
  description: Multi-line delimiter formats (YAML frontmatter, horizontal rules) framing system sections
123
123
  - field: user_input
124
124
  operator: regex
@@ -8,7 +8,7 @@ author: ATR Community (MiroFish Predicted)
8
8
  date: 2026/03/11
9
9
  schema_version: '0.1'
10
10
  detection_tier: pattern
11
- maturity: stable
11
+ maturity: test
12
12
  severity: high
13
13
  references:
14
14
  owasp_llm:
@@ -74,7 +74,7 @@ detection:
74
74
  description: 'A Cyrillic letter that renders as Latin sitting directly against Latin text, which is the paypal-with-a- Cyrillic-a shape. The Cyrillic side is restricted to those seven letters rather than the whole block, and the reason is the engine''s own normalization: foldConfusables maps exactly those homoglyphs to Latin, so "Управляет расписанием" folds to "Yпpabляet pacпиcahиem" and the fold itself manufactures the mixed-script adjacency this condition looks for. Matching the full Cyrillic block therefore fired on ordinary Russian through the folded copy while the raw copy was clean. Restricting to the homoglyph set makes the condition immune to that: after folding, any Cyrillic still present is by definition not a homoglyph.'
75
75
  - field: user_input
76
76
  operator: regex
77
- value: '[\uF900-\uFAFF][a-zA-Z]{2,}|[a-zA-Z]{2,}[\uF900-\uFAFF]'
77
+ value: '[\uF900-\uFAFF][a-zA-Z]{2}|[a-zA-Z]{2}[\uF900-\uFAFF]'
78
78
  description: 'CJK COMPATIBILITY ideographs (U+F900-U+FAFF) mixed with Latin text. These codepoints are canonically equivalent to ordinary unified ideographs under NFC/NFKC, so a literal blocklist or logging layer sees a different string than the renderer - that mismatch is the spoof. The CJK Unified ranges (U+3400-U+4DBF, U+4E00-U+9FFF) are deliberately excluded: a unified ideograph next to Latin is standard bilingual technical writing, not a homoglyph.'
79
79
  - field: user_input
80
80
  operator: regex
@@ -71,7 +71,7 @@ detection:
71
71
  description: Teaching examples containing actual injection payloads
72
72
  - field: content
73
73
  operator: regex
74
- value: (?i)(?:attack|threat|injection)[\s_-]*(?:pattern|vector|type)s?\s*[:=]\s*[\[\{]?\s*["']?(?:prompt[\s_-]?inject|role[\s_-]?hijack|jailbreak|memory[\s_-]?tamper|goal[\s_-]?hijack|data[\s_-]?exfil|context[\s_-]?pollut|tool[\s_-]?poison|instruction[\s_-]?override)
74
+ value: (?i)(?:attack|threat|injection)[\s_-]*(?:pattern|vector|type)s?\s*[:=]\s*(?:[\[\{]\s*)?["']?(?:prompt[\s_-]?inject|role[\s_-]?hijack|jailbreak|memory[\s_-]?tamper|goal[\s_-]?hijack|data[\s_-]?exfil|context[\s_-]?pollut|tool[\s_-]?poison|instruction[\s_-]?override)
75
75
  description: Enumeration of attack patterns in a key-value format LLMs may follow
76
76
  condition: any
77
77
  false_positives:
@@ -66,8 +66,8 @@ detection:
66
66
  description: Persona establishment with unrestricted AI character
67
67
  - field: content
68
68
  operator: regex
69
- value: (?i)(two\s+responses?|dual\s+response|both\s+responses?|\w+:\s*.*\w+:)\s*.{0,80}(normal|regular|standard|censored|restricted|safe|filtered)\s+(and|&)\s+(unleashed|unrestricted|uncensored|unfiltered|unlimited|jailbroken|raw|unaligned)
70
- description: Dual response format requesting both safe and unsafe outputs
69
+ value: (?i)(two\s+responses?|dual\s+response|both\s+responses?|\w:\s*(?:[^\s\\][^\r\n\\]*)?\w:)\s*(?:\S.{0,79})?(normal|regular|standard|censored|restricted|safe|filtered)\s+(and|&)\s+(unleashed|unrestricted|uncensored|unfiltered|unlimited|jailbroken|raw|unaligned)
70
+ description: 'Dual response format requesting both safe and unsafe outputs. The two-labels alternative ("GPT: ... DAN:") is meant to stay on one line. It used `.*`, which stops at a line break in raw text but not in JSON-encoded text, where a line break is the two characters backslash-n: on a JSON-encoded document the run spanned the whole input from every `word:`, so cost grew faster than the square of its length (32K chars: 4.7s per call, 81K chars: 50s) and this rule and its duplicate ATR-2026-00233 were 38% of all CPU in the benign-corpus FP scan. `[^\r\n\\]*` stops at a line break or at a JSON escape, which restores the one-line meaning in both encodings and is RE2-native. Long single-line text was still quadratic: the run overlapped the `\w+:` after it, and the whitespace runs before the run and before the 80-character window overlapped what follows them. Each label is now its last word character and colon, and the run and the window each start on a non-space, which matches exactly the same strings in linear time.'
71
71
  - field: content
72
72
  operator: regex
73
73
  value: (?i)(guidelines?\s+have\s+been\s+(replaced|removed|disabled|overridden|suspended)|replace\s+(normal|openai|anthropic|standard|default)\s+guidelines?|new\s+guidelines?|different\s+guidelines?|custom\s+guidelines?)\s*.{0,60}(policies|rules|restrictions|constraints|limitations|guardrails)
@@ -1,9 +1,9 @@
1
1
  title: Structured Dual-Response Jailbreak with Command System
2
2
  id: ATR-2026-00233
3
3
  rule_version: 1
4
- status: experimental
4
+ status: deprecated
5
5
  description: |
6
- Detects sophisticated jailbreak attempts that establish a fictional unrestricted AI persona (like "UnleashedGPT", "DAN", etc.) combined with dual-response formatting requesting both normal and "unleashed" outputs. These attacks create structured command systems for ongoing safety bypass and often include detailed policy override instructions, constraint removal claims, and authority impersonation. The attack establishes a persistent jailbreak framework rather than a single harmful request. Pattern crystallized from garak probe atr:missed-sample showing structured persona-based bypass with command infrastructure.
6
+ DEPRECATED: duplicate of ATR-2026-00228, with the same detection until 00228's condition 1 was rewritten to run in linear time; retained as a tombstone, all detection is handled by ATR-2026-00228. Detects sophisticated jailbreak attempts that establish a fictional unrestricted AI persona (like "UnleashedGPT", "DAN", etc.) combined with dual-response formatting requesting both normal and "unleashed" outputs. These attacks create structured command systems for ongoing safety bypass and often include detailed policy override instructions, constraint removal claims, and authority impersonation. The attack establishes a persistent jailbreak framework rather than a single harmful request. Pattern crystallized from garak probe atr:missed-sample showing structured persona-based bypass with command infrastructure.
7
7
  author: ATR Community (via NVIDIA garak in-the-wild corpus)
8
8
  date: 2026/04/18
9
9
  schema_version: '0.1'
@@ -80,7 +80,7 @@ detection:
80
80
  description: Social-engineering framing ("secure system message") combined with encoding keyword
81
81
  - field: tool_response
82
82
  operator: regex
83
- value: (?:^|\\n|\n)\s*[A-Za-z0-9+/]{80,}={0,3}(?:\\n|\s)+(?:\w+\s+){0,2}(?:decode|decoded|translate|interpret|execute|run|follow)\b
83
+ value: (?:^|\\n|\n)[^\S\n]*[A-Za-z0-9+/]{80,}={0,3}(?:\\n|\s)+(?:\w+\s+){0,2}(?:decode|decoded|translate|interpret|execute|run|follow)\b
84
84
  description: Long base64-alphabet blob (80+ chars) immediately followed by a decode/execute verb
85
85
  condition: any
86
86
  false_positives:
@@ -67,15 +67,15 @@ detection:
67
67
  description: Core "ignore previous instructions" imperative - latent injection hallmark
68
68
  - field: tool_response
69
69
  operator: regex
70
- value: (?:ignore|skip)\s+(?:\w+\s+){0,3}(?:and\s+)?(?:just|only|simply)?\s*(?:translate|print|output|return|say|respond\s+with|reply\s+with)\s+(?:this\s+(?:as|sentence\s+as)|["\x27])
70
+ value: (?:ignore|skip)\s+(?:\w+\s+){0,3}(?:and\s+)?(?:(?:just|only|simply)\s*)?(?:translate|print|output|return|say|respond\s+with|reply\s+with)\s+(?:this\s+(?:as|sentence\s+as)|["\x27])
71
71
  description: 'Latent injection variant: override original task and emit specific payload'
72
72
  - field: tool_response
73
73
  operator: regex
74
- value: '<(?:translated\s+sentence|output|response|reply|answer)\s+in\s+(?:target\s+language|[a-z]+\s+language)>\s*(?:\r?\n|\\n)+\s*(?:user|assistant|system)\s*:'
74
+ value: '<(?:translated\s+sentence|output|response|reply|answer)\s+in\s+(?:target\s+language|[a-z]+\s+language)>(?:[^\S\n]*\n\s*|\s*\\n(?:(?:\r?\n)*\\n)*\s*)(?:user|assistant|system)\s*:'
75
75
  description: Fake turn-marker embedded in translate input to spoof multi-turn context
76
76
  - field: tool_response
77
77
  operator: regex
78
- value: (?:^|\n|\\n)\s*>+\s*(?:ignore|disregard|instead|actually|override|new\s+instruction)
78
+ value: (?:^|\n|\\n)[^\S\n]*>+\s*(?:ignore|disregard|instead|actually|override|new\s+instruction)
79
79
  description: Quote-block prefix used to visually separate injection from surrounding text (garak separator pattern)
80
80
  - field: tool_response
81
81
  operator: regex
@@ -74,7 +74,7 @@ detection:
74
74
  description: Classic "ignore previous instructions" embedded in retrieved text
75
75
  - field: tool_response
76
76
  operator: regex
77
- value: (?:^|\n)\s*---+\s*\n\s*(?:CONFIDENTIAL|INTERNAL|HIDDEN|IMPORTANT|NOTE|INSTRUCTION)\s*:\s*(?:ignore|disregard|forget|you\s+(?:must|should|are\s+required))
77
+ value: (?:^|\n)[^\S\n]*---+[^\S\n]*\n\s*(?:CONFIDENTIAL|INTERNAL|HIDDEN|IMPORTANT|NOTE|INSTRUCTION)\s*:\s*(?:ignore|disregard|forget|you\s+(?:must|should|are\s+required))
78
78
  description: HR-document separator followed by instruction override - garak resume probe pattern
79
79
  - field: tool_response
80
80
  operator: regex
@@ -67,11 +67,11 @@ detection:
67
67
  conditions:
68
68
  - field: tool_response
69
69
  operator: regex
70
- value: (?:^|\n)\s*(?:IGNORE|DISREGARD|FORGET|OVERRIDE)\s+(?:ALL\s+)?(?:PREVIOUS|PRIOR|ABOVE|EARLIER|THE\s+(?:PREVIOUS|ABOVE|PRIOR))\s+(?:INSTRUCTIONS?|PROMPTS?|CONTEXT|TEXT|DIRECTIONS?|GUIDELINES?|RULES?|CONSTRAINTS?)\b
70
+ value: (?:^|\n)[^\S\n]*(?:IGNORE|DISREGARD|FORGET|OVERRIDE)\s+(?:ALL\s+)?(?:PREVIOUS|PRIOR|ABOVE|EARLIER|THE\s+(?:PREVIOUS|ABOVE|PRIOR))\s+(?:INSTRUCTIONS?|PROMPTS?|CONTEXT|TEXT|DIRECTIONS?|GUIDELINES?|RULES?|CONSTRAINTS?)\b
71
71
  description: Screaming-stop / ignore-all variant — ALL-CAPS imperative at line start, Perez promptinject taxonomy
72
72
  - field: tool_response
73
73
  operator: regex
74
- value: (?:\n\s*-{3,}\s*\n|\n\s*={3,}\s*\n|\n\s*\*{3,}\s*\n|\n\s*#{3,}\s*\n)\s*(?:IGNORE|DISREGARD|NEW\s+(?:TASK|INSTRUCTION|OBJECTIVE)|ACTUALLY)
74
+ value: (?:\n[^\S\n]*-{3,}[^\S\n]*\n|\n[^\S\n]*={3,}[^\S\n]*\n|\n[^\S\n]*\*{3,}[^\S\n]*\n|\n[^\S\n]*#{3,}[^\S\n]*\n)\s*(?:IGNORE|DISREGARD|NEW\s+(?:TASK|INSTRUCTION|OBJECTIVE)|ACTUALLY)
75
75
  description: Delimiter escape sequence (---, ===, ***) followed by instruction override — Perez delimiter attack
76
76
  - field: tool_response
77
77
  operator: regex
@@ -79,11 +79,11 @@ detection:
79
79
  description: Nevermind-override attack — "nevermind the above, instead say X" Perez ignore variant
80
80
  - field: tool_response
81
81
  operator: regex
82
- value: (?:(?:please\s+)?ignore\s+(?:the\s+)?(?:above|previous|prior|that)\s+(?:and|then)?\s+(?:instead\s+)?(?:say|print|output|write|respond\s+with|tell\s+me))\s+["\x27]?(?:I\s+hate\s+humans|kill\s+humans|[A-Z\s]{10,}|PWNED|HACKED|JAILBROKEN)\b
82
+ value: (?:(?:please\s+)?ignore\s+(?:the\s+)?(?:above|previous|prior|that)\s(?:\s*(?:and|then))?\s+(?:instead\s+)?(?:say|print|output|write|respond\s+with|tell\s+me))(?:\s+["\x27]?(?:I\s+hate\s+humans|kill\s+humans|PWNED|HACKED|JAILBROKEN)|\s+["\x27][A-Z\s]{10,}|\s[A-Z\s]{10,})\b
83
83
  description: Ignore-say/ignore-print with known garak rogue strings (hate-humans, kill-humans, long-prompt)
84
84
  - field: tool_response
85
85
  operator: regex
86
- value: (?:^|\n)\s*(?:>\s*)+(?:IGNORE|DISREGARD|NEW\s+INSTRUCTION|OVERRIDE|SYSTEM\s*:)
86
+ value: (?:^|\n)[^\S\n]*(?:>\s*)+(?:IGNORE|DISREGARD|NEW\s+INSTRUCTION|OVERRIDE|SYSTEM\s*:)
87
87
  description: 'Markdown blockquote-wrapped instruction override — > IGNORE / > SYSTEM: prefix used to visually isolate injection'
88
88
  condition: any
89
89
  false_positives:
@@ -84,7 +84,7 @@ detection:
84
84
  description: 'Hyphenated "ass-istant is not functioning / offline" — the fake assistant-failure declaration that legitimizes the AI takeover; from inthewild corpus #83 #84'
85
85
  - field: tool_response
86
86
  operator: regex
87
- value: (?:_+\s*\{|>>)\s*_+\s*_+\s*System\s+annou
87
+ value: (?:_\s*\{|>>)\s*_+(?:_|\s+_+)\s*System\s+annou
88
88
  description: '"_ { >> _ _ System annou" — decorative wrapper preceding the hyphenated system announcement in inthewild corpus prompts #37 #68; the bracket-and-underscore framing mimics a privileged system context'
89
89
  condition: any
90
90
  false_positives:
@@ -77,11 +77,11 @@ detection:
77
77
  description: Backspace cluster in tool response — two or more \x08 in tool output indicates injected content attempting to hide instructions from human log review
78
78
  - field: user_input
79
79
  operator: regex
80
- value: '[A-Za-z]{2,}\x08[A-Za-z]'
80
+ value: '[A-Za-z]{2}\x08[A-Za-z]'
81
81
  description: Word characters immediately followed by backspace then different char — inline character-substitution via backspace; "safe\x08x" renders as "safx" visually but model sees "safe\x08x"
82
82
  - field: user_input
83
83
  operator: regex
84
- value: \x08+\s*(?:ignore|forget|disregard|pretend|act\s+as|you\s+are|bypass|override|jailbreak|do\s+not\s+follow|instead)\b
84
+ value: \x08\s*(?:ignore|forget|disregard|pretend|act\s+as|you\s+are|bypass|override|jailbreak|do\s+not\s+follow|instead)\b
85
85
  description: Backspace immediately before jailbreak keyword — attacker hides harmful instruction prefix with deletion chars so reviewers see only the benign remainder
86
86
  condition: any
87
87
  false_positives:
@@ -63,15 +63,15 @@ detection:
63
63
  conditions:
64
64
  - field: user_input
65
65
  operator: regex
66
- value: (?:^|[\n\r])\s*(?:None|True|False|null|undefined|[A-Z]|var|str|[sxyz])\s*=\s*["'`][^"'`\n]{3,120}["'`]\s*[\n;][\s\S]{0,300}?(?:print|output|return|concat|join|emit|reveal|exec|eval)\b
66
+ value: (?:^|[\n\r])[^\S\n\r]*(?:None|True|False|null|undefined|[A-Z]|var|str|[sxyz])\s*=\s*["'`][^"'`\n]{3,120}["'`](?:\s*;|[^\S\n]*\n)\s*(?:\S[\s\S]{0,299}?)?(?:print|output|return|concat|join|emit|reveal|exec|eval)\b
67
67
  description: Attack-shaped variable assignment with quoted payload followed by output / exec action
68
68
  - field: user_input
69
69
  operator: regex
70
- value: (?:^|[\n\r])\s*(?:[A-Z]|[sxyz]|var|str|None|True|False|null|undefined)\s*=\s*["'`][^"'`\n]{1,30}["'`]\s*[\n\r]+\s*(?:[A-Z]|[sxyz]|var|str|None|True|False|null|undefined)\s*=\s*["'`][^"'`\n]{1,30}["'`]
70
+ value: (?:^|[\n\r])[^\S\n\r]*(?:[A-Z]|[sxyz]|var|str|None|True|False|null|undefined)\s*=\s*["'`][^"'`\n]{1,30}["'`][^\S\n\r]*[\n\r]\s*(?:[A-Z]|[sxyz]|var|str|None|True|False|null|undefined)\s*=\s*["'`][^"'`\n]{1,30}["'`]
71
71
  description: Two-or-more attack-shaped variable assignments with quoted payloads
72
72
  - field: user_input
73
73
  operator: regex
74
- value: (?:^|[\n\r])\s*(?:None|True|False|null|undefined)\s*=\s*["'`]
74
+ value: (?:^|[\n\r])[^\S\n\r]*(?:None|True|False|null|undefined)\s*=\s*["'`]
75
75
  description: Reserved-name reassignment to quoted string (Python None/True/False or JS null/undefined)
76
76
  response:
77
77
  actions:
@@ -74,11 +74,11 @@ detection:
74
74
  conditions:
75
75
  - field: user_input
76
76
  operator: regex
77
- value: (?i)<[a-zA-Z]+[^>]+on[a-zA-Z]+\s*="?javascript\s*:\s*(javascript\s*:)?\s*alert\s*\([^)]*\)
77
+ value: (?i)<[a-zA-Z][^>]+on[a-zA-Z]+\s*="?javascript\s*:\s*(?:(javascript\s*:)\s*)?alert\s*\([^)]*\)
78
78
  description: HTML event handler (on*=javascript:alert) XSS payload
79
79
  - field: user_input
80
80
  operator: regex
81
- value: '(?i)style\s*="[^"]*\\x[0-9a-fA-F]{2,}[^"]*expression\s*\(\s*javascript\s*:'
81
+ value: '(?i)style\s*="[^"]*\\x[0-9a-fA-F]{2}[^"]*expression\s*\(\s*javascript\s*:'
82
82
  description: 'CSS expression injection with backslash-hex-encoded whitespace before javascript: protocol'
83
83
  - field: user_input
84
84
  operator: regex
@@ -94,7 +94,7 @@ detection:
94
94
  description: img onerror with backslash-hex control-char prefix before javascript:alert
95
95
  - field: user_input
96
96
  operator: regex
97
- value: (?i)['"`>]+\s*<\s*img[^>]+\\x[0-9a-fA-F]{2,}onerror\s*=\s*javascript\s*:\s*alert
97
+ value: (?i)['"`>]\s*<\s*img[^>]+\\x[0-9a-fA-F]{2,}onerror\s*=\s*javascript\s*:\s*alert
98
98
  description: Quote-breaking prefix followed by img with hex-encoded whitespace before onerror
99
99
  condition: any
100
100
  false_positives:
@@ -86,7 +86,7 @@ detection:
86
86
  description: Template-slot GENDER/AGE/CHARACTER parameter injection (DAN character-definition pattern)
87
87
  - field: user_input
88
88
  operator: regex
89
- value: (?:[.-]+\s+){15,}[.-]+
89
+ value: '[.-]\s+(?:[.-]+\s+){14}[.-]'
90
90
  description: Extended Morse code sequence (15+ tokens) used as encoded instruction payload
91
91
  - field: user_input
92
92
  operator: regex