agent-threat-rules 4.1.5 → 4.2.1

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 (248) hide show
  1. package/CHANGELOG.md +751 -1
  2. package/README.md +356 -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-00501-data-exfiltration-via-markdown-image-and-link-url-injection.yaml +16 -2
  156. package/rules/context-exfiltration/ATR-2026-00505-system-prompt-extraction-instruction-dump-request.yaml +6 -4
  157. package/rules/context-exfiltration/ATR-2026-00702-ipi-credential-exfil-via-agent-action.yaml +1 -1
  158. package/rules/context-exfiltration/ATR-2026-00707-ipi-file-exfil-with-destroy-or-tamper.yaml +1 -1
  159. package/rules/context-exfiltration/ATR-2026-00851-indirect-pi-financial-payment-exfil.yaml +1 -1
  160. package/rules/context-exfiltration/ATR-2026-01457-sysprompt-completion-clone-attack.yaml +1 -1
  161. package/rules/context-exfiltration/ATR-2026-01462-sysprompt-override-pseudo-admin.yaml +1 -1
  162. package/rules/context-exfiltration/ATR-2026-01463-imend-imsystem-prompt-injection-format.yaml +1 -1
  163. package/rules/context-exfiltration/ATR-2026-01606-ssrf-internal-network-scan.yaml +1 -1
  164. package/rules/context-exfiltration/ATR-2026-02847-policy-justified-exfil-to-email.yaml +1 -1
  165. package/rules/context-exfiltration/ATR-2026-02855-cross-email-exfil-relay.yaml +79 -0
  166. package/rules/context-exfiltration/ATR-2026-02861-exfil-send-email-with-body-directive.yaml +83 -0
  167. package/rules/context-exfiltration/ATR-2026-02866-idna-label-separator-in-fetch-url-host.yaml +104 -0
  168. package/rules/excessive-autonomy/ATR-2026-00500-ssrf-via-agent-url-fetch-instruction.yaml +12 -2
  169. package/rules/excessive-autonomy/ATR-2026-00710-ipi-physical-access-grant.yaml +1 -1
  170. package/rules/model-abuse/ATR-2026-01897-host-sabotage.yaml +2 -2
  171. package/rules/model-security/ATR-2026-00433-modelcache-torch-load-deserialization-rce.yaml +1 -1
  172. package/rules/privilege-escalation/ATR-2026-00040-privilege-escalation.yaml +1 -1
  173. package/rules/privilege-escalation/ATR-2026-00436-enclave-vm-sandbox-escape-rce.yaml +1 -1
  174. package/rules/privilege-escalation/ATR-2026-01601-sql-injection-destructive-ddl.yaml +3 -3
  175. package/rules/privilege-escalation/ATR-2026-01612-debug-mode-privilege-escalation.yaml +1 -1
  176. package/rules/privilege-escalation/ATR-2026-02867-identifier-typed-tool-argument-dot-dot-path-segment.yaml +106 -0
  177. package/rules/prompt-injection/ATR-2026-00004-system-prompt-override.yaml +2 -2
  178. package/rules/prompt-injection/ATR-2026-00080-encoding-evasion.yaml +1 -1
  179. package/rules/prompt-injection/ATR-2026-00086-visual-spoofing.yaml +1 -1
  180. package/rules/prompt-injection/ATR-2026-00203-context-pollution-skill-description.yaml +1 -1
  181. package/rules/prompt-injection/ATR-2026-00228-structured-jailbreak.yaml +2 -2
  182. package/rules/prompt-injection/ATR-2026-00233-structured-jailbreak.yaml +2 -2
  183. package/rules/prompt-injection/ATR-2026-00256-base-n-encoding-jailbreak.yaml +1 -1
  184. package/rules/prompt-injection/ATR-2026-00264-latent-injection-translation.yaml +3 -3
  185. package/rules/prompt-injection/ATR-2026-00265-latent-injection-rag-document.yaml +1 -1
  186. package/rules/prompt-injection/ATR-2026-00282-perez-prompt-injection-hijack.yaml +4 -4
  187. package/rules/prompt-injection/ATR-2026-00321-hyphenated-system-instruction-injection.yaml +1 -1
  188. package/rules/prompt-injection/ATR-2026-00394-backspace-deletion-character-injection.yaml +2 -2
  189. package/rules/prompt-injection/ATR-2026-00446-variable-assignment-payload-injection.yaml +3 -3
  190. package/rules/prompt-injection/ATR-2026-00476-garak-web-injection-javascript-alert-1.yaml +3 -3
  191. package/rules/prompt-injection/ATR-2026-00481-garak-dan-mixedunassigned.yaml +1 -1
  192. package/rules/prompt-injection/ATR-2026-00489-garak-encoding-javascript-alert-1.yaml +3 -3
  193. package/rules/prompt-injection/ATR-2026-00503-fake-error-state-takeover-unrestricted-replacement-bot.yaml +4 -2
  194. package/rules/prompt-injection/ATR-2026-00508-escape-delimiter-wrapped-goal-hijacking-in-user-input-prompt.yaml +3 -3
  195. package/rules/prompt-injection/ATR-2026-00512-rules-file-backdoor-injection.yaml +1 -1
  196. package/rules/prompt-injection/ATR-2026-01005-many-shot-repetition-override.yaml +2 -2
  197. package/rules/prompt-injection/ATR-2026-01006-payload-split-string-concat-injection.yaml +2 -2
  198. package/rules/prompt-injection/ATR-2026-01015-evasion-refusal-suppression.yaml +1 -1
  199. package/rules/prompt-injection/ATR-2026-01016-evasion-response-priming-forced-opener.yaml +1 -1
  200. package/rules/prompt-injection/ATR-2026-01026-evasion-unicode-glitch-token-anomaly.yaml +2 -2
  201. package/rules/prompt-injection/ATR-2026-01304-indirect-injection-carrier-important-override.yaml +1 -1
  202. package/rules/prompt-injection/ATR-2026-01759-dos-new-important-instructions-injection-in-document.yaml +1 -1
  203. package/rules/prompt-injection/ATR-2026-01865-llmail-fake-email-boundary-marker.yaml +1 -1
  204. package/rules/prompt-injection/ATR-2026-02010-emoji-only-payload.yaml +2 -2
  205. package/rules/prompt-injection/ATR-2026-02815-injected-halt-order-canned-reply-dos.yaml +80 -0
  206. package/rules/prompt-injection/ATR-2026-02820-tool-result-orders-agent-to-hide-its-own-action.yaml +106 -0
  207. package/rules/prompt-injection/ATR-2026-02858-context-suppression-directive.yaml +73 -0
  208. package/rules/prompt-injection/ATR-2026-02859-tool-output-agent-role-reassignment.yaml +71 -0
  209. package/rules/prompt-injection/ATR-2026-02860-forged-instruction-boundary-marker.yaml +70 -0
  210. package/rules/prompt-injection/ATR-2026-02862-fake-chat-template-turn-injection.yaml +79 -0
  211. package/rules/skill-compromise/ATR-2026-00060-skill-impersonation.yaml +1 -1
  212. package/rules/skill-compromise/ATR-2026-00063-skill-chain-attack.yaml +2 -2
  213. package/rules/skill-compromise/ATR-2026-00064-over-permissioned-skill.yaml +1 -1
  214. package/rules/skill-compromise/ATR-2026-00066-parameter-injection.yaml +2 -2
  215. package/rules/skill-compromise/ATR-2026-00149-skill-exfil-compound.yaml +6 -6
  216. package/rules/skill-compromise/ATR-2026-00223-reverse-shell-dropper.yaml +2 -2
  217. package/rules/skill-compromise/ATR-2026-01755-backdoor-pot-linguistic-trigger-phrase.yaml +1 -1
  218. package/rules/skill-compromise/ATR-2026-01756-backdoor-pot-symbol-emoticon-trigger.yaml +1 -1
  219. package/rules/skill-compromise/ATR-2026-02261-code-credential-exfil-chain.yaml +1 -1
  220. package/rules/tool-poisoning/ATR-2026-00012-unauthorized-tool-call.yaml +23 -23
  221. package/rules/tool-poisoning/ATR-2026-00013-tool-ssrf.yaml +16 -5
  222. package/rules/tool-poisoning/ATR-2026-00161-important-tag-cross-tool-shadowing.yaml +1 -1
  223. package/rules/tool-poisoning/ATR-2026-00277-echo-template-command-injection.yaml +2 -2
  224. package/rules/tool-poisoning/ATR-2026-00494-garak-exploitation-mixedunassigned.yaml +4 -4
  225. package/rules/tool-poisoning/ATR-2026-00521-shell-command-injection-agent-tool-context.yaml +1 -1
  226. package/rules/tool-poisoning/ATR-2026-00581-mcp-tool-rug-pull-post-approval-redefinition.yaml +1 -1
  227. package/rules/tool-poisoning/ATR-2026-01303-tool-schema-enumeration-social-engineering.yaml +1 -1
  228. package/rules/tool-poisoning/ATR-2026-01307-mcp-dns-rebinding-attack.yaml +2 -2
  229. package/rules/tool-poisoning/ATR-2026-01775-semantic-mcp-tool-manifest-poisoning.yaml +1 -1
  230. package/rules/tool-poisoning/ATR-2026-01932-shadow-undeclared-mcp-server-registration.yaml +1 -1
  231. package/rules/tool-poisoning/ATR-2026-02025-mcp-full-schema-poisoning-nondescription-field.yaml +1 -1
  232. package/rules/tool-poisoning/ATR-2026-02817-untrusted-content-dictates-tool-arguments.yaml +83 -0
  233. package/rules/tool-poisoning/ATR-2026-02864-non-canonical-ipv4-host-in-url-tool-argument.yaml +102 -0
  234. package/rules/tool-poisoning/ATR-2026-02865-read-only-utility-write-flag-in-command-argument.yaml +157 -0
  235. package/rules/tool-poisoning/ATR-2026-02868-ssrf-ipv6-transition-address-embedded-private-ipv4.yaml +107 -0
  236. package/rules/tool-poisoning/ATR-2026-02870-invisible-control-before-directive.yaml +94 -0
  237. package/spec/README.md +6 -3
  238. package/spec/atr-event-v1.0.md +13 -8
  239. package/spec/atr-method-v1.1.md +2 -2
  240. package/spec/category-registry/gemara/README.md +102 -0
  241. package/spec/category-registry/gemara/ai-agent-capability-catalog.yaml +157 -0
  242. package/spec/category-registry/gemara/atr-attack-vector-catalog.yaml +130 -0
  243. package/spec/category-registry/gemara/atr-detection-control-catalog.yaml +327 -0
  244. package/spec/category-registry/gemara/atr-threat-catalog.yaml +246 -0
  245. package/spec/category-registry/gemara/src/editorial.yaml +743 -0
  246. package/spec/mappings/README.md +1 -1
  247. package/spec/mappings/atr-to-nist-csf-2.0.md +5 -4
  248. package/spec/schema/event.schema.json +1 -1
@@ -1,9 +1,9 @@
1
1
  title: SSRF via Agent Tool Calls
2
2
  id: ATR-2026-00013
3
- rule_version: 2
3
+ rule_version: 4
4
4
  status: experimental
5
5
  description: |
6
- Detects high-confidence Server-Side Request Forgery (SSRF) that targets cloud CREDENTIAL / metadata services or uses deliberate obfuscation — the cases where an agent has no legitimate reason to make the request. Detection covers: AWS/GCP/Azure/DigitalOcean/Oracle/Alibaba metadata and IMDS credential endpoints and token headers, OBFUSCATED loopback encodings (hex/octal), exotic URI schemes (file, gopher, dict, tftp, ldap) targeting internal addresses, DNS-rebinding service hostnames, IPv6 mapped/ULA loopback, redirect-parameter SSRF to internal targets, and internal-redirect URL shorteners. NOTE (v2, precision): plain localhost / 127.0.0.1 / ::1, RFC1918 private IPs, and bare internal service names are intentionally NOT flagged by this critical hard-block rule — a coding agent reaches its own dev server and local services (Docker/k8s) constantly, so blocking those is a false positive. Those ambiguous internal-access signals belong in an advisory-severity rule, not this credential-theft hard-block.
6
+ Detects high-confidence Server-Side Request Forgery (SSRF) that targets cloud CREDENTIAL / metadata services or uses deliberate obfuscation — the cases where an agent has no legitimate reason to make the request. Detection covers: AWS/GCP/Azure/DigitalOcean/Oracle/Alibaba metadata and IMDS credential endpoints and token headers, OBFUSCATED loopback encodings (hex/octal), exotic URI schemes (file, gopher, dict, tftp, ldap) targeting internal addresses, DNS-rebinding service hostnames, IPv4-mapped IPv6 forms of loopback and private IPv4, redirect-parameter SSRF to internal targets, and internal-redirect URL shorteners. NOTE (v2, precision): plain localhost / 127.0.0.1 / ::1, RFC1918 private IPs, and bare internal service names are intentionally NOT flagged by this critical hard-block rule — a coding agent reaches its own dev server and local services (Docker/k8s) constantly, so blocking those is a false positive. Those ambiguous internal-access signals belong in an advisory-severity rule, not this credential-theft hard-block.
7
7
  author: ATR Community
8
8
  date: 2026/03/08
9
9
  schema_version: '0.1'
@@ -24,6 +24,10 @@ references:
24
24
  cve:
25
25
  - CVE-2019-5418
26
26
  - CVE-2021-21311
27
+ - CVE-2026-55096
28
+ external:
29
+ - https://nvd.nist.gov/vuln/detail/CVE-2026-55096
30
+ - https://github.com/leshchenko1979/fast-mcp-telegram/security/advisories/GHSA-xr72-j7vj-vp7g
27
31
  compliance:
28
32
  nist_ai_rmf:
29
33
  - subcategory: MS.2.7
@@ -95,27 +99,34 @@ detection:
95
99
  description: Exotic URI schemes targeting internal addresses
96
100
  - field: tool_args
97
101
  operator: regex
98
- value: (?i)(https?://)?[a-zA-Z0-9-]+\.(xip\.io|nip\.io|sslip\.io|localtest\.me|vcap\.me|lvh\.me|lacolhost\.com|127\.0\.0\.1\.[a-z]+\.\w+)(:\d+)?
102
+ value: (?i)(https?://)?[a-zA-Z0-9-]{1,63}\.(xip\.io|nip\.io|sslip\.io|localtest\.me|vcap\.me|lvh\.me|lacolhost\.com|127\.0\.0\.1\.[a-z]+\.\w+)(:\d+)?
99
103
  description: DNS rebinding services that resolve to internal IPs
104
+ - field: tool_args
105
+ operator: regex
106
+ value: (?i)\b(?:https?|wss?|ftp):(?:\\?/){2}(?:[^\s/\\@"'<>]{1,64}@)?(?:localtest\.me|lvh\.me|vcap\.me|lacolhost\.com)\.?(?:[:/?#"'\s\\\],;)>|]|$)
107
+ description: 'APEX loopback-wildcard domains used as a URL host. localtest.me, lvh.me, vcap.me and lacolhost.com resolve to 127.0.0.1 at the apex as well as on every subdomain, so a hostname-string SSRF denylist that does not resolve DNS lets https://localtest.me/admin reach loopback services (CVE-2026-55096, fast-mcp-telegram send_message files[]). The pattern above only covers the subdomain form; this one requires a URL scheme directly before the apex host (plain "//" or JSON-escaped "\/\/", optional userinfo, optional trailing dot) and then a host terminator character (: / ? # quote whitespace backslash ] , ; ) > |) or end of input, so prose mentions and look-alike hosts such as localtest.mesh.example.com, lvh.media, vcap.me.uk or lvh.me-cdn.net do not match. The terminator is consumed rather than asserted with a lookahead so the pattern stays RE2-portable. Known limitations (not covered): protocol-relative //localtest.me/admin with no scheme; other apex loopback domains such as localho.st or fuf.me; attacker-owned domains whose A record points at an internal IP (needs DNS resolution, not possible at the pattern layer). Known false positives: a developer reaching their own dev server through the lvh.me alias (curl http://lvh.me:3000/...), and a free-text search query that quotes the URL https://localtest.me - the existing subdomain condition above already flags app.lvh.me:3000, so this is consistent with it.'
100
108
  - field: tool_args
101
109
  operator: regex
102
110
  value: (?i)(redirect|redir|url|next|return|returnUrl|returnTo|continue|dest|destination|go|goto|target|link|out|view|ref|callback|forward)\s*=\s*(https?%3A%2F%2F|https?://)(localhost|127\.0\.0\.1|10\.|172\.(1[6-9]|2[0-9])|192\.168|169\.254|0\.0\.0|\[?::1\]?)
103
111
  description: URL redirect parameters targeting internal addresses
104
112
  - field: tool_args
105
113
  operator: regex
106
- value: (?i)(https?://)?\[?(::1|::ffff:127\.0\.0\.1|::ffff:10\.|::ffff:172\.(1[6-9]|2[0-9]|3[01])|::ffff:192\.168|fc[0-9a-f]{2}:|fd[0-9a-f]{2}:)\]?(:\d+)?
107
- description: IPv6 loopback, IPv4-mapped, and unique local addresses (fc/fd)
114
+ value: (?i)(?:^|[^0-9a-f:]|%5b)\[?(?:(?:0{1,4}:){1,4}:|::|(?:0{1,4}:){5})ffff:(?:127\.\d{1,3}\.\d{1,3}\.\d{1,3}|10\.|172\.(?:1[6-9]|2[0-9]|3[01])\.|192\.168\.)
115
+ description: 'IPv4-mapped IPv6 forms (::ffff:a.b.c.d, also written 0::ffff:, 0:0::ffff: or fully expanded 0:0:0:0:0:ffff:) of loopback (127/8) and RFC 1918 IPv4, an obfuscation that slips past filters written for dotted IPv4. The address must start the token (start of input, a character that is not a hex digit or colon, or a percent-encoded bracket %5B), so the suffix of a longer IPv6 address does not count. Known limits: a mapped address directly after a colon (unbracketed host:port:addr syntax such as curl --resolve x:80:::ffff:127.0.0.1) and a JSON-escaped bracket (\u005b) are not matched; the hex form ::ffff:7f00:1, IPv4-compatible ::127.0.0.1 and NAT64 64:ff9b:: forms are left to ATR-2026-02868; ::ffff:0.0.0.0 and ::ffff:100.64.0.0/10 are not covered. Plain ::1 and unique local addresses (fc00::/7) are not matched, for the same reason plain localhost, 127.0.0.1 and RFC 1918 are not (see the v2 note in the description): a coding agent reaches its own dev server on [::1] and private services on ULA all the time. v3 matched both with no token boundary, so the tail of a public 6to4 address (2002:cb00:7101::1), ::10, and Oracle APEX URLs (:::190) matched as loopback.'
108
116
  - field: tool_args
109
117
  operator: regex
110
118
  value: (?i)(https?://)?(bit\.ly|tinyurl\.com|t\.co|goo\.gl|is\.gd|v\.gd|rb\.gy|cutt\.ly|short\.io|tiny\.cc)/[a-zA-Z0-9]+
111
119
  description: URL shorteners that may redirect to internal services
112
120
  condition: any
113
121
  false_positives:
122
+ - Logs and diagnostics pasted into a tool argument that report IPv4 peers in IPv4-mapped form, as dual-stack sockets do on Linux (netstat / ss / lsof output, Node "connect ECONNREFUSED ::ffff:127.0.0.1:6379", Express req.ip ::ffff:192.168.1.10, nginx or MySQL messages with ::ffff:172.17.0.1). Loopback addresses of system resolvers such as ::ffff:127.0.0.53 match too, since 127/8 is covered.
114
123
  - Agents with legitimate access to internal services explicitly allowlisted
115
124
  - Development environments where localhost access is expected
116
125
  - Private network tools designed for internal infrastructure management
117
126
  - Cloud management tools that legitimately query metadata endpoints
118
127
  - Service mesh tools that use .internal or .consul DNS names by design
128
+ - Developers who use the lvh.me / localtest.me / vcap.me / lacolhost.com loopback aliases for their own dev server (common in the Rails community, e.g. curl http://lvh.me:3000/users/sign_in) - both the apex and the subdomain forms are flagged, unlike plain localhost which v2 deliberately allows. Maintainers should decide whether these aliases belong in this hard-block rule or an advisory-severity rule.
129
+ - Free-text tool arguments (search queries, notes) that quote a full https://localtest.me style URL while discussing it rather than requesting it.
119
130
  response:
120
131
  actions:
121
132
  - block_tool
@@ -21,7 +21,7 @@ references:
21
21
  - AML.T0051.001 - Indirect
22
22
  - AML.T0053 - AI Agent Tool Invocation
23
23
  - 'AML.T0110.000 - AI Agent Tool Poisoning: Definition and Instructions'
24
- - AML.T0104 - Publish Poisoned AI Agent Tool
24
+ - 'AML.T0115.002 - Publish Poisoned AI Artifacts: AI Agent Tools'
25
25
  safe_mcp:
26
26
  - SAF-T1102
27
27
  - SAF-T1001
@@ -65,11 +65,11 @@ detection:
65
65
  conditions:
66
66
  - field: tool_response
67
67
  operator: regex
68
- value: (?:i\s+am\s+(?:an?\s+)?(?:administrator|admin|sysadmin|root|superuser)\s+testing|when\s+I\s+prefix\s+(?:a\s+statement|(?:it\s+)?with)\s+["\x27]?ECHO[\s:]["\x27]?)\s*,?\s*(?:you\s+should\s+)?(?:respond|reply|echo|output|repeat|return)\s+(?:with\s+)?exactly\s+what\s+follows
68
+ value: (?:i\s+am\s+(?:an?\s+)?(?:administrator|admin|sysadmin|root|superuser)\s+testing|when\s+I\s+prefix\s+(?:a\s+statement|(?:it\s+)?with)\s+["\x27]?ECHO[\s:]["\x27]?)(?:\s*,)?\s*(?:you\s+should\s+)?(?:respond|reply|echo|output|repeat|return)\s+(?:with\s+)?exactly\s+what\s+follows
69
69
  description: 'Garak ECHO_TEMPLATE admin preamble: "administrator testing echo — when prefixed with ECHO: respond exactly"'
70
70
  - field: tool_response
71
71
  operator: regex
72
- value: (?:^|\n)\s*ECHO\s*:\s*(?:\{\{[^}]{1,200}\}\}|[`$]\([^)]{1,200}\)|\$\{[^}]{1,200}\}|<\?(?:php|=)[^?]{1,200}\?>|import\s+os|__import__|subprocess|eval\s*\(|exec\s*\()
72
+ value: (?:^|\n)[^\S\n]*ECHO\s*:\s*(?:\{\{[^}]{1,200}\}\}|[`$]\([^)]{1,200}\)|\$\{[^}]{1,200}\}|<\?(?:php|=)[^?]{1,200}\?>|import\s+os|__import__|subprocess|eval\s*\(|exec\s*\()
73
73
  description: 'ECHO: prefix followed by template expression, command substitution, or code execution payload'
74
74
  - field: tool_response
75
75
  operator: regex
@@ -80,15 +80,15 @@ detection:
80
80
  description: SQL UNION SELECT injection for data exfiltration
81
81
  - field: user_input
82
82
  operator: regex
83
- value: (?i)(and|or|if)\s*\(?\s*(substring|substr|mid|left|right|ascii|char|ord)\s*\(.{0,40}\)\s*=\s*['"]?[a-z0-9]|and\s*if\s*\(.{0,60}(sleep|waitfor\s+delay|benchmark)\s*\(
83
+ value: (?i)(and|or|if)\s*(?:\(\s*)?(substring|substr|mid|left|right|ascii|char|ord)\s*\(.{0,40}\)\s*=\s*['"]?[a-z0-9]|and\s*if\s*\(.{0,60}(sleep|waitfor\s+delay|benchmark)\s*\(
84
84
  description: Blind boolean/time-based SQL injection via character extraction and delay functions
85
85
  - field: user_input
86
86
  operator: regex
87
- value: (?i)'\s*;?\s*insert\s+into\s+[a-z_]+\s*(?:\([^)]{0,100}\)\s*)?values\s*\(
87
+ value: (?i)'\s*(?:;\s*)?insert\s+into\s+[a-z_]+\s*(?:\([^)]{0,100}\)\s*)?values\s*\(
88
88
  description: SQL INSERT INTO injection payload (column list optional)
89
89
  - field: user_input
90
90
  operator: regex
91
- value: (?i)[0-9]+\s*;\s*drop\s+table\s+[a-z_]+\s*(--|;|/\*)
91
+ value: (?i)[0-9]\s*;\s*drop\s+table\s+[a-z_]+\s*(--|;|/\*)
92
92
  description: SQL DROP TABLE destructive injection
93
93
  - field: user_input
94
94
  operator: regex
@@ -100,7 +100,7 @@ detection:
100
100
  description: SQL server shutdown or command execution via stored procedure
101
101
  - field: user_input
102
102
  operator: regex
103
- value: (?i)\(lambda\s+[a-z_,\s]+:\s*\[+[^\]]{0,200}(s\.connect|socket\.connect|os\.system|subprocess|exec|eval).{0,100}\d{4,5}\)
103
+ value: (?i)\(lambda\s[a-z_,\s]+:\s*\[+(?:[^\]\[][^\]]{0,199})?(s\.connect|socket\.connect|os\.system|subprocess|exec|eval).{0,100}\d{4,5}\)
104
104
  description: Python lambda-based reverse shell or code execution payload
105
105
  condition: any
106
106
  false_positives:
@@ -1,6 +1,6 @@
1
1
  title: Shell Command Injection in Agent Tool Context
2
2
  id: ATR-2026-00521
3
- rule_version: 1
3
+ rule_version: 2
4
4
  status: stable
5
5
  description: |
6
6
  Detects prompts that embed shell command injection payloads within legitimate-sounding task requests to an AI agent with shell/code execution tools. The canonical shape is a benign-looking task followed by a chained shell command that exfiltrates data (env vars, .env files, logs, credentials) to an attacker-controlled URL via curl/wget/nc or Python urllib. Seen in promptfoo redteam shell-injection plugin (7 confirmed samples). The structural detection generalizes from specific evil.com URLs to the structural pattern that distinguishes injection from legitimate shell use: a shell chaining operator (;, &&, ||, $(...), backtick, or 'then') followed immediately by a dangerous network/execution tool (curl, wget, nc, bash, sh, python, powershell, cmd). This covers the data-exfiltration shape without requiring specific domain names. The pipe-to-nc and pipe-to-bash variants are covered by a separate condition.
@@ -20,7 +20,7 @@ references:
20
20
  mitre_atlas:
21
21
  - AML.T0053 - AI Agent Tool Invocation
22
22
  - AML.T0051.001 - Indirect
23
- - AML.T0104 - Publish Poisoned AI Agent Tool
23
+ - 'AML.T0115.002 - Publish Poisoned AI Artifacts: AI Agent Tools'
24
24
  vulnerablemcp_id:
25
25
  - tool-poisoning-rce-rug-pull
26
26
  external:
@@ -56,7 +56,7 @@ detection:
56
56
  conditions:
57
57
  - field: content
58
58
  operator: regex
59
- value: (?i)(?:list|show|give|tell\s+me|enumerate)\s+(?:me\s+)?(?:all\s+)?(?:the\s+)?(?:internal|hidden|admin(?:-only)?|privileged?|every)?\s*(?:functions?\s+or\s+tools?|tools?\s+(?:you\s+can\s+call|or\s+functions?)|internal\s+(?:functions?|tools?|api\s+endpoints?))[^.]{0,80}(?:you\s+can\s+call|admin-only|including\s+(?:any\s+)?admin|with\s+their\s+parameters|access\s+to)
59
+ value: (?i)(?:list|show|give|tell\s+me|enumerate)\s+(?:me\s+)?(?:all\s+)?(?:the\s+)?(?:(?:internal|hidden|admin(?:-only)?|privileged?|every)\s*)?(?:functions?\s+or\s+tools?|tools?\s+(?:you\s+can\s+call|or\s+functions?)|internal\s+(?:functions?|tools?|api\s+endpoints?))[^.]{0,80}(?:you\s+can\s+call|admin-only|including\s+(?:any\s+)?admin|with\s+their\s+parameters|access\s+to)
60
60
  description: Request to enumerate the agent's own internal/admin tools or functions
61
61
  - field: content
62
62
  operator: regex
@@ -62,11 +62,11 @@ detection:
62
62
  conditions:
63
63
  - field: content
64
64
  operator: regex
65
- value: (?i)\b[a-zA-Z0-9.-]+\.(?:rebind\.network|rbndr\.us|rebinder\.com|1u\.ms)\b
65
+ value: (?i)\b[a-zA-Z0-9.-]{1,253}\.(?:rebind\.network|rbndr\.us|rebinder\.com|1u\.ms)\b
66
66
  description: Known DNS rebinding service hostname (rebind.network, rbndr.us, etc.)
67
67
  - field: content
68
68
  operator: regex
69
- value: (?i)[\w.-]*(?:1time|forever|ttl\d+|0ttl)[\w.-]+(?:127\.0\.0\.1|192\.168\.\d+\.\d+|10\.\d+\.\d+\.\d+|172\.(?:1[6-9]|2\d|3[0-1])\.\d+\.\d+)
69
+ value: (?i)(?:1time|forever|ttl\d+|0ttl)[\w.-]{1,253}(?:127\.0\.0\.1|192\.168\.\d+\.\d+|10\.\d+\.\d+\.\d+|172\.(?:1[6-9]|2\d|3[0-1])\.\d+\.\d+)
70
70
  description: Time-based DNS rebinding hostname pattern combining public IP with loopback/private IP
71
71
  - field: content
72
72
  operator: regex
@@ -34,7 +34,7 @@ references:
34
34
  - ASI02:2026
35
35
  mitre_atlas:
36
36
  - AML.T0053 - AI Agent Tool Invocation
37
- - AML.T0019 - Publish Poisoned Datasets
37
+ - 'AML.T0115.000 - Publish Poisoned AI Artifacts: Datasets'
38
38
  - AML.T0051.001 - Indirect
39
39
  - 'AML.T0110.000 - AI Agent Tool Poisoning: Definition and Instructions'
40
40
  compliance:
@@ -19,7 +19,7 @@ references:
19
19
  - ASI09:2026
20
20
  mitre_atlas:
21
21
  - AML.T0010 - AI Supply Chain Compromise
22
- - AML.T0104 - Publish Poisoned AI Agent Tool
22
+ - 'AML.T0115.002 - Publish Poisoned AI Artifacts: AI Agent Tools'
23
23
  mitre_attack:
24
24
  - T1195.002 - Compromise Software Supply Chain
25
25
  - T1036 - Masquerading
@@ -20,7 +20,7 @@ references:
20
20
  mitre_atlas:
21
21
  - AML.T0051.001 - Indirect
22
22
  - 'AML.T0110.000 - AI Agent Tool Poisoning: Definition and Instructions'
23
- - AML.T0104 - Publish Poisoned AI Agent Tool
23
+ - 'AML.T0115.002 - Publish Poisoned AI Artifacts: AI Agent Tools'
24
24
  safe_mcp:
25
25
  - SAF-T1001
26
26
  research:
@@ -0,0 +1,83 @@
1
+ title: Untrusted Tool Result Dictates a Tool Call by Schema Parameter Name
2
+ id: ATR-2026-02817
3
+ rule_version: 1
4
+ status: experimental
5
+ description: |
6
+ Detects untrusted content inside a tool result that speaks the agent's OWN tool-schema vocabulary: it names the target function and binds each parameter by its literal schema name to a chosen value, then asks the assistant to construct exactly those arguments and issue the call. This is not an imperative wish ("please transfer 500 dollars") — which ATR already covers — it is a serialised call specification planted in a bill description, a review body or a message body, so the model's remaining work is transcription rather than intent formation. Source: AutoDojo variant generation over the AgentDojo banking and slack suites (agentdojo/variant_generation/variants/banking/.../injections.json and banking_rlhammer.json). Measured before authoring: 4 verbatim variants of this shape produced 1 hit across 785 rules, and that hit was ATR-2026-00504 firing incidentally on the words "full ... overview ... tools", not on the call-spec structure. TWO CONJUNCTS, BOTH REQUIRED. (1) An AGENT-DIRECTED request to emit the call. A bare "call the send_money function with the parameter recipient set to ..." is deliberately NOT matched, because that is exactly how API reference documentation, OpenAPI descriptions, SDK guides, changelog migration notes and bug-report repro steps read; six such benign twins were authored and all six match the parameter-binding condition alone. (2) TWO OR MORE named parameter bindings within 300 characters, which is what makes the text a call spec rather than a sentence that happens to mention an argument. CHANNEL IS PART OF THE DETECTION, NOT AN ACCIDENT. agent_source.type is mcp_exchange, so EVENT_TYPE_TO_SOURCE routes only tool_response and tool_call events here and llm_input is never evaluated. That is load-bearing: a user who types "I would like you to call the geocode function with the parameter address set to ..." is making an ordinary direct request, and it matches both conditions. It is benign because of WHO said it, and the event type is the only place that fact exists. Do not widen this rule to llm_io.
7
+ author: ATR Project
8
+ date: 2026/08/24
9
+ schema_version: '1.0'
10
+ detection_tier: pattern
11
+ maturity: test
12
+ severity: high
13
+ references:
14
+ owasp_llm:
15
+ - LLM01:2025
16
+ owasp_agentic:
17
+ - ASI01:2026
18
+ - ASI02:2026
19
+ mitre_atlas:
20
+ - AML.T0051 - LLM Prompt Injection
21
+ - AML.T0053 - LLM Plugin Compromise
22
+ papers:
23
+ - 'AutoDojo: automated variant generation for AgentDojo prompt-injection suites — repo: https://github.com/xhOwenMa/AutoDojo, agentdojo/variant_generation/variants/banking/anthropic/claude-haiku-4.5/no_defense/injections.json and banking_rlhammer.json'
24
+ - 'Debenedetti et al., AgentDojo: A Dynamic Environment to Evaluate Prompt Injection Attacks and Defenses for LLM Agents (arXiv:2406.13352)'
25
+ compliance:
26
+ nist_ai_rmf:
27
+ - subcategory: MS.2.7
28
+ context: A call specification planted in untrusted tool output is a prompt-injection payload aimed at the agent's action surface; MS.2.7 requires that resilience to such injection be evaluated and documented, and this rule supplies the runtime evidence.
29
+ strength: primary
30
+ - subcategory: MG.2.3
31
+ context: MG.2.3 requires mechanisms to disengage or override an AI system that behaves outside intended use; detecting dictated tool arguments is the trigger condition for that override before the call is issued.
32
+ strength: secondary
33
+ - subcategory: MS.1.1
34
+ context: MS.1.1 requires that risks be measured against intended use; a tool call whose arguments originate in retrieved third-party data is outside the agent's intended authority chain, which this rule makes measurable.
35
+ strength: secondary
36
+ iso_42001:
37
+ - clause: '8.1'
38
+ context: ISO/IEC 42001 Clause 8.1 (operational planning and control, including control of externally provided processes) is operationalised by detecting third-party content that attempts to originate the agent's tool calls.
39
+ strength: primary
40
+ - clause: 6.1.2
41
+ context: ISO/IEC 42001 Clause 6.1.2 (AI risk assessment) identifies untrusted-input-driven action as a treated risk; this rule is the corresponding detective control.
42
+ strength: secondary
43
+ eu_ai_act:
44
+ - article: '15'
45
+ context: Article 15 (accuracy, robustness and cybersecurity) requires high-risk AI systems to resist third-party attempts to alter their use or outputs; a dictated tool call is a direct alteration of use, detected here before execution.
46
+ strength: primary
47
+ - article: '14'
48
+ context: Article 14 (human oversight) requires that a natural person can intervene before consequential automated action; flagging an externally dictated call spec is what creates that intervention point.
49
+ strength: secondary
50
+ - article: '9'
51
+ context: Article 9 (risk management system) requires identified risks to be addressed by appropriate measures; this rule is a runtime risk-treatment control for indirect prompt injection targeting tool invocation.
52
+ strength: secondary
53
+ tags:
54
+ category: tool-poisoning
55
+ subcategory: dictated-tool-arguments
56
+ scan_target: content
57
+ confidence: medium
58
+ agent_source:
59
+ type: mcp_exchange
60
+ framework:
61
+ - any
62
+ provider:
63
+ - any
64
+ detection:
65
+ conditions:
66
+ - field: content
67
+ operator: regex
68
+ value: (?:\bI\s+(?:would\s+like|want|need|am\s+asking)\s+(?:you|the\s+(?:assistant|agent|ai|model|bot))\s+to\s+(?:call|invoke|execute|run|trigger|use)\b|\b(?:can|could|would|will)\s+you\s+(?:please\s+)?(?:construct|build|create|assemble|prepare|produce|form)\b[^.\n]{0,80}?\b(?:argument|parameter)s?\b[^.\n]{0,80}?\b(?:call|invoke|execute|trigger)\b|\b(?:have|let|ask)\s+the\s+(?:assistant|agent|ai|model|bot)\s+(?:to\s+)?(?:call|invoke|execute|trigger)\b|\bthe\s+(?:assistant|agent|ai|model|bot)\s+(?:should|must|needs\s+to|is\s+to)\s+(?:call|invoke|execute|trigger)\s+the\s+[A-Za-z_][A-Za-z0-9_]{1,40}\s+(?:function|tool|api|method|endpoint|command)\b)
69
+ description: The retrieved content asks an assistant/agent to construct and issue the call — the conjunct that separates a planted call spec from API reference documentation
70
+ - field: content
71
+ operator: regex
72
+ value: (?:\bthe\s+[A-Za-z_][A-Za-z0-9_]{1,40}\s+(?:parameter|argument|field)\b|\b(?:parameter|argument|field)\s+[A-Za-z_][A-Za-z0-9_]{1,40}\s+(?:\bset\s+to|=|\bas|\bto)\b|\bpassing\s+[^.\n]{0,60}?\bto\s+the\s+[A-Za-z_][A-Za-z0-9_]{1,40}\s+(?:parameter|argument|field)\b)[\s\S]{0,300}?(?:\bthe\s+[A-Za-z_][A-Za-z0-9_]{1,40}\s+(?:parameter|argument|field)\b|\b(?:parameter|argument|field)\s+[A-Za-z_][A-Za-z0-9_]{1,40}\s+(?:\bset\s+to|=|\bas|\bto)\b|\bpassing\s+[^.\n]{0,60}?\bto\s+the\s+[A-Za-z_][A-Za-z0-9_]{1,40}\s+(?:parameter|argument|field)\b)
73
+ description: Two or more named parameter bindings within 300 chars, i.e. the text is a serialised call specification rather than prose mentioning an argument
74
+ condition: all
75
+ false_positives:
76
+ - A support ticket, bug report or vendor email in which a human legitimately asks the agent to run a specific tool with specific arguments. The text is indistinguishable; what differs is whether the requester is authorised, which is not a property of the content.
77
+ - Security research or vendor writing that quotes an AutoDojo banking/slack injection variant verbatim.
78
+ - Agent-framework tutorials retrieved as documentation that phrase an example as a request to the assistant.
79
+ response:
80
+ actions:
81
+ - alert
82
+ message_template: |
83
+ [ATR-2026-02817] A tool result contains a fully specified tool call — target function plus parameter-by-parameter argument bindings — addressed to the assistant. Arguments originating in retrieved third-party data must not be executed without human confirmation.
@@ -0,0 +1,102 @@
1
+ title: Non-Canonical Numeric IPv4 Host in a URL-Typed Tool Argument (SSRF Filter Bypass)
2
+ id: ATR-2026-02864
3
+ rule_version: 1
4
+ status: experimental
5
+ description: |
6
+ Detects an agent or node tool call whose URL-typed argument names its host as a NON-CANONICAL numeric IPv4 literal: a bare decimal integer (http://2130706433/), a bare octal integer (http://017700000001/), a bare hex integer (http://0x7f000001/), a dotted address whose first part is octal or hex (http://0177.0.0.1/, http://0x7f.0.0.1/), or the two- and three-part short forms (http://127.1/, http://127.0.1/, http://10.1/). URL parsers and the OS resolver expand every one of these into an ordinary address such as 127.0.0.1, 10.0.0.1 or 169.254.169.254, but a deny-list that only recognises the four-part dotted-decimal spelling does not, so the request reaches loopback, LAN or cloud-metadata services the filter was meant to stop.
7
+ This is the bypass core of CVE-2026-101883 (OpenClaw Windows Node through 2026.9.4): the canvas.present capability skipped the URL risk evaluation that canvas.navigate enforced, and the regex-based check that did exist only matched dotted-decimal private ranges. Anyone with gateway or agent access could send canvas.present with {"url": "http://2130706433:8080/admin"} and make the node's WebView issue the request from the user's machine. The fix commit 16528aa added CanvasUrlSafety, whose tests enumerate exactly these encodings. The same parser differential applies to any URL-typed argument of any tool (fetch, browse, open_url, webhook targets), so the rule is not keyed to the canvas tool name.
8
+ SCOPE AND LIMITS, stated honestly. The rule matches only when the URL is a JSON string value with a quoted key ("url":"..."), a quoted element of a JSON array ({"urls":["..."]}), or the whole argument string, so prose that quotes the payload does not fire. A single trailing dot after the host (http://2130706433./) is accepted because WHATWG/Chromium URL parsers (the WebView2 used by the Windows node) drop the empty final label and still resolve it to 127.0.0.1. JSON-escaped slashes after the scheme (http:\/\/0x7f000001\/, as produced by PHP json_encode) are also accepted. It deliberately does NOT match canonical dotted-decimal loopback or private addresses (127.0.0.1, 10.x, 192.168.x), 0.0.0.0, the bare "0" host, or the 100.64.0.0/10 CGNAT / Tailscale range, even though the upstream fix blocks all of them: coding agents and node canvases legitimately open local dev servers, LAN devices and tailnet dashboards constantly, and those values are byte-for-byte the same shape as the attack. IPv4-mapped IPv6, [::1] and ULA ([fd00::1]) hosts are matched by ATR-2026-00013. That rule lists only a few hard-coded hex/octal loopback strings (0x7f000001, 0x7f.0x0.0x0.0x1, 017700000001 and similar), so the overlap is limited to those exact strings; general hex forms such as http://0x7f.1:9222/ are not matched by ATR-2026-00013 (its own evasion_tests list 0x7f.1 as a gap) and are covered here. Unicode full-width dots, percent-encoded hosts, zero-padded dotted-decimal octets (http://127.000.000.001/), scheme-relative URLs (//2130706433/) and DNS names that resolve to internal addresses are out of scope.
9
+ CWE-918 (Server-Side Request Forgery), CWE-1286 (Improper Validation of Syntactic Correctness of Input).
10
+ author: ATR Community (CVE sync)
11
+ date: 2026/10/22
12
+ schema_version: '0.1'
13
+ detection_tier: pattern
14
+ maturity: test
15
+ severity: high
16
+ references:
17
+ cve:
18
+ - CVE-2026-101883
19
+ ghsa:
20
+ - GHSA-7vch-pmw9-3g4q
21
+ euvd:
22
+ - EUVD-2026-90256
23
+ owasp_llm:
24
+ - LLM06:2025
25
+ owasp_agentic:
26
+ - ASI02:2026
27
+ mitre_atlas:
28
+ - AML.T0049 - Exploit Public-Facing Application
29
+ - AML.T0053 - AI Agent Tool Invocation
30
+ mitre_attack:
31
+ - T1090 - Proxy
32
+ - T1046 - Network Service Discovery
33
+ external:
34
+ - https://github.com/openclaw/openclaw-windows-node/security/advisories/GHSA-7vch-pmw9-3g4q
35
+ - https://github.com/openclaw/openclaw-windows-node/commit/16528aadaa45d7bc6718b07ccf8b01f3eb033ad1
36
+ - https://www.vulncheck.com/advisories/openclaw-windows-node-through-2026.9.4-ssrf-via-canvas-present
37
+ - https://euvd.enisa.europa.eu/vulnerability/EUVD-2026-90256
38
+ metadata_provenance:
39
+ cve: human-reviewed
40
+ ghsa: human-reviewed
41
+ owasp_llm: human-reviewed
42
+ owasp_agentic: human-reviewed
43
+ mitre_atlas: human-reviewed
44
+ mitre_attack: human-reviewed
45
+ compliance:
46
+ eu_ai_act:
47
+ - article: '15'
48
+ context: Article 15 requires accuracy, robustness and cybersecurity appropriate to the intended purpose. A URL argument whose host is spelled as a decimal, octal or short-form IPv4 literal is a known way to slip past a dotted-decimal deny-list; this rule provides detection evidence supporting the Article 15 robustness obligation at the agent-to-tool boundary while the receiving tool remains unpatched.
49
+ strength: primary
50
+ - article: '9'
51
+ context: Article 9 risk management must account for the network reach an agent's tools give it. Runtime evidence that tool calls are steering a node's browser or fetcher at encoded internal addresses feeds the risk register for that surface.
52
+ strength: secondary
53
+ nist_ai_rmf:
54
+ - function: Measure
55
+ subcategory: MS.2.7
56
+ context: MS.2.7 requires AI system security and resilience to be evaluated and documented. Inspecting each URL-typed tool argument for non-canonical IPv4 host encodings is a measurable, per-invocation control against SSRF filter bypass rather than an assumption that every tool canonicalises hosts correctly.
57
+ strength: primary
58
+ - function: Manage
59
+ subcategory: MG.3.2
60
+ context: MG.3.2 requires pre-trained models and third-party components to be monitored. Node capabilities and MCP tools that fetch URLs are third-party components whose host validation the deployer cannot audit; flagging encoded internal hosts in their arguments is the monitoring control.
61
+ strength: secondary
62
+ iso_42001:
63
+ - clause: '8.1'
64
+ context: Clause 8.1 operational planning and control covers the tools an AI system invokes. This rule is an operational control applied to every URL-typed tool argument, independent of the tool's own URL validation.
65
+ strength: primary
66
+ - clause: '8.3'
67
+ context: Clause 8.3 AI risk treatment requires controls proportionate to identified risks. Because one encoded host can expose loopback admin panels or cloud metadata from the user's machine, inspecting URL hosts at call time is a proportionate treatment.
68
+ strength: secondary
69
+ tags:
70
+ category: tool-poisoning
71
+ subcategory: ssrf-encoded-ip-host
72
+ scan_target: tool_args
73
+ confidence: medium
74
+ source: cve-disclosure
75
+ vendor_sources: openclaw-windows-node-cve-2026-101883
76
+ agent_source:
77
+ type: tool_call
78
+ framework:
79
+ - any
80
+ provider:
81
+ - any
82
+ detection:
83
+ condition: any
84
+ method: pattern
85
+ conditions:
86
+ - field: tool_args
87
+ operator: regex
88
+ value: (?:^|\\?"[A-Za-z_][A-Za-z0-9_.-]{0,40}\\?"\s{0,3}:\s{0,3}\\?"|[\[,]\s{0,3}\\?")(?:https?|wss?|ftp):\\?/\\?/(?:[^/\s"\x27@?#\\]{1,64}@)?(?:\d{8,10}|0[0-7]{8,11}|0x[0-9a-f]{1,8}|0(?:[0-7]{1,3}|x[0-9a-f]{1,2})(?:\.(?:0x[0-9a-f]{1,2}|\d{1,4})){1,3}|\d{1,3}\.\d{1,8}|\d{1,3}\.\d{1,3}\.\d{1,5})\.?(?:[:/?#"\x27\\\s\]]|$)
89
+ description: A URL that is a quoted JSON value, a quoted JSON array element (or the whole argument) whose host is a decimal integer, octal integer, hex integer, octal/hex-first-part dotted address, or a two/three-part short IPv4 form - every spelling that resolves to an IPv4 address while evading a dotted-decimal deny-list
90
+ false_positives:
91
+ - Security test suites, SSRF fuzzing harnesses and CVE reproductions that deliberately pass encoded hosts in a URL argument will match; that is the intended behaviour for a detection corpus.
92
+ - A serialized tool call or JSON document quoted verbatim inside an article is the same bytes as the attack and still matches. Prose that mentions the URL without a quoted key does not.
93
+ - Embedded or industrial devices whose documentation tells users to reach them by a short-form address (http://10.1/) would match; this is rare and the short form is itself a canonicalisation hazard.
94
+ response:
95
+ actions:
96
+ - alert
97
+ - snapshot
98
+ actions_rationale: 'response-action eligibility (docs/RESPONSE-ACTION-ELIGIBILITY.md): new rule with no benign-corpus FP measurement beyond the gate; ceiling = observe.'
99
+ auto_response_threshold: high
100
+ message_template: |
101
+ [ATR-2026-02864] HIGH: a URL-typed tool argument names its host as a non-canonical numeric IPv4 literal (decimal / octal / hex integer, octal or hex dotted part, or short form). These spellings resolve to internal addresses such as 127.0.0.1 or 169.254.169.254 while slipping past dotted-decimal deny-lists - the CVE-2026-101883 canvas.present SSRF bypass. Canonicalise the host before applying URL policy.
102
+ confidence: 72
@@ -0,0 +1,157 @@
1
+ title: Read-Only Allow-Listed Utility Invoked With a File-Write or State-Changing Option in a Command Argument
2
+ id: ATR-2026-02865
3
+ rule_version: 1
4
+ status: experimental
5
+ description: |
6
+ Detects an agent or MCP tool call whose command-string argument starts with a utility that command allow-lists commonly classify as read-only (sort, uniq, diff, date, hostname, file) and gives it the option or operand that makes the utility itself write a file, run a helper program, or change system state. No shell metacharacter is involved: the allowed binary opens the destination on its own, so filters that only look for ; | && $( ) never see it.
7
+ This is the shape reported as CVE-2026-105789 / GHSA-85w2-wggf-rw49 against Microsoft UFO before 3.0.9. The execute_command tool of the Linux MCP server (ufo/client/mcp/http_servers/linux_mcp_server.py) accepted a free-form command string and allowed sort and uniq as read-only commands, so 'sort -o <file>' or the optional second uniq operand created or overwrote any file writable by the server process (agent configuration, shell startup files). The fix (commit 4f79362) removed sort and added per-command argument policies; its regression tests (tests/test_linux_mcp_command_policy.py) list the rejected forms used here. The command string is produced by the model, so a prompt injection that steers the next tool call is enough to reach it.
8
+ Six layers, each one utility's state-changing form: (1) sort with -o / an -o short-option cluster / --output (and its unique prefixes --o, --out ...), or --compress-program naming anything other than a real compressor (gzip, pigz, bzip2, xz, lz4, zstd, ...): sort executes that program, which turns a read-only allow-list entry into code execution; (2) diff with --output / --out / -o; (3) uniq with two non-option operands, where the second is the output file; option arguments of -f / -s / -w are consumed so 'uniq -f 2 data.txt' is not read as two operands; (4) date with -s / --set (and --se, --s) or a bare operand that is a valid MMDDhhmm[[CC]YY][.ss] timestamp (month 01-12, day 01-31, hour 00-23, minute 00-59), both of which set the system clock; a YYYYMMDD string such as 'date 20261022' is not a valid month and does not match; (5) hostname given a new name as its only operand, or -F / --file; (6) file with --compile (or its unique prefixes --co, --comp ...), which writes a compiled magic database (.mgc) into the working directory.
9
+ Scope and limits: the utility must be the FIRST token of a JSON string value whose key is command-like: command, cmd, cmd_line, command_line, cmdline, commandline, shell, script, exec, args, argv, optionally prefixed by a word ending in '_' or '-' (bash_command, shell_cmd) or by bash, shell, sh, run, exec, raw or full (shellCommand, runCmd). Keys that merely end in those letters (transcript, subscript) do not count. The utility may be prefixed by sudo or a /usr/bin, /bin or ./ path. A JSON-escaped tab (\t) between tokens is treated as whitespace, because the shell splits on it; an escaped newline is not, because it ends the command. Commands reached after a pipe, ';', '&&' or a newline, passed as an argv array, or wrapped by env / nice / timeout are out of scope (shell-metacharacter rules cover the chained forms). file -C cannot be told apart from the read-only file -c because the engine matches case-insensitively, so only the long --compile form is covered. file -z / --uncompress, which the same fix also rejects, is not covered: it runs only libmagic's fixed decompressor list, not an attacker-chosen program, and 'file -z archive.gz' is ordinary read-only use. uniq operands that are quoted are not matched. CWE-88, CWE-184.
10
+ RE2 portability: every condition compiles under RE2 (checked with Go regexp). The earlier lookarounds were replaced without changing behaviour: trailing lookaheads now consume the terminator, the uniq option/operand lookaheads became explicit alternatives, and the --compress-program compressor exception became a positive witness generated from the compressor/path trie. Measured equivalent to the lookaround version on 2.4M generated command strings and an exhaustive 1.48M-string sweep of the --compress-program value forms. The trade-off is size: Layer 1 is about 2.4 KB because a finite exception list has no short RE2 spelling.
11
+ Known false positive: in a general-purpose shell tool where writing files is allowed, the ordinary write forms of these utilities match exactly like the attack, for example 'sort -o sorted.txt data.txt', in-place sorting with 'sort -u -o names.txt names.txt', and 'uniq -c sorted.txt counts.txt'. The rule reports that a read-only-looking utility was used to write, not intent, which is why severity is medium and the response is observe-only.
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: medium
18
+ references:
19
+ cve:
20
+ - CVE-2026-105789
21
+ ghsa:
22
+ - GHSA-85w2-wggf-rw49
23
+ cwe:
24
+ - CWE-88
25
+ - CWE-184
26
+ owasp_llm:
27
+ - LLM06:2025
28
+ - LLM03:2025
29
+ owasp_agentic:
30
+ - ASI02:2026
31
+ - ASI05:2026
32
+ - ASI04:2026
33
+ mitre_atlas:
34
+ - AML.T0053 - AI Agent Tool Invocation
35
+ mitre_attack:
36
+ - 'T1565.001 - Data Manipulation: Stored Data Manipulation'
37
+ - 'T1546.004 - Event Triggered Execution: Unix Shell Configuration Modification'
38
+ - T1202 - Indirect Command Execution
39
+ external:
40
+ - https://github.com/microsoft/UFO/security/advisories/GHSA-85w2-wggf-rw49
41
+ - https://github.com/microsoft/UFO/pull/349
42
+ - https://github.com/microsoft/UFO/commit/4f793622794f5d47810d54bed431c61f6a781dd6
43
+ - https://github.com/microsoft/UFO/releases/tag/v3.0.9
44
+ - https://euvd.enisa.europa.eu/vulnerability/EUVD-2026-93406
45
+ metadata_provenance:
46
+ cve: euvd-sync
47
+ cwe: human-reviewed
48
+ owasp_llm: human-reviewed
49
+ owasp_agentic: human-reviewed
50
+ mitre_atlas: human-reviewed
51
+ mitre_attack: human-reviewed
52
+ compliance:
53
+ eu_ai_act:
54
+ - article: '15'
55
+ context: Article 15 requires cybersecurity appropriate to the intended purpose. An agent whose command tool trusts sort, uniq, diff, date, hostname or file as read-only can be steered into overwriting its own configuration or changing system state; flagging those utilities' write and set forms provides detection evidence supporting Article 15 robustness at the agent-to-OS boundary.
56
+ strength: primary
57
+ - article: '9'
58
+ context: Article 9 risk management must identify how an agent's tools can be misused. Matches from this rule provide detection evidence supporting Article 9 by showing when a command allow-list's read-only classification was exceeded through a utility's own options, a risk that first-token allow-lists do not capture.
59
+ strength: secondary
60
+ nist_ai_rmf:
61
+ - function: Measure
62
+ subcategory: MS.2.7
63
+ context: MS.2.7 requires security and resilience to be evaluated and documented. Inspecting each command-tool invocation for file-write and state-changing options of allow-listed utilities is a measurable per-call control rather than an assumption that the allow-list is complete.
64
+ strength: primary
65
+ - function: Manage
66
+ subcategory: MG.3.2
67
+ context: MG.3.2 covers monitoring of third-party components in operation. The vulnerable execute_command tool ships with an agent framework the deployer did not write; monitoring the commands it actually receives is the operational check on that component.
68
+ strength: secondary
69
+ iso_42001:
70
+ - clause: '8.1'
71
+ context: Clause 8.1 operational control over externally provided processes covers the MCP servers an agent invokes. This rule is applied to every command those servers receive, independent of the server's own argument policy.
72
+ strength: primary
73
+ - clause: '8.3'
74
+ context: Clause 8.3 AI risk treatment requires controls proportionate to the risk. Because one sort -o can overwrite the agent's own configuration, runtime detection of the write form is a proportionate treatment alongside upgrading the framework.
75
+ strength: secondary
76
+ tags:
77
+ category: tool-poisoning
78
+ subcategory: read-only-utility-write-option
79
+ scan_target: tool_args
80
+ confidence: medium
81
+ source: cve-disclosure
82
+ vendor_sources: microsoft-ufo-cve-2026-105789
83
+ agent_source:
84
+ type: mcp_exchange
85
+ framework:
86
+ - mcp
87
+ - any
88
+ provider:
89
+ - any
90
+ detection:
91
+ condition: any
92
+ method: pattern
93
+ false_positives:
94
+ - 'Known false positive: a general-purpose shell tool where the user genuinely asks the agent to write sorted or de-duplicated output to a file produces the same tool call as the attack, for example sort -o sorted.txt data.txt, in-place sort -u -o names.txt names.txt, or uniq -c sorted.txt counts.txt. The rule cannot tell intent; it reports that a utility commonly allow-listed as read-only was used in its write form.'
95
+ - Administrative agents that are meant to set the clock or hostname (date -s, hostname new-name) will match.
96
+ - Building a custom magic database with file -C -m magic --compile in a development shell will match.
97
+ - Security test suites and CVE reproductions that pass these command strings to a tool will match, which is intended for a detection corpus.
98
+ conditions:
99
+ - field: content
100
+ operator: regex
101
+ value: \\{0,7}"(?:\w{0,24}?[_-]|bash|shell|sh|run|exec|raw|full)?(?:command_line|commandline|cmd_line|cmdline|command|cmd|shell|script|exec|args?|argv)\\{0,7}"\s*:\s*\\{0,7}"\s{0,16}(?:sudo(?:\s|\\(?:\\\\?)?t){1,64})?(?:/(?:usr/)?(?:local/)?s?bin/|\./)?sort(?:(?:\s|\\(?:\\\\?)?t){1,64}[^\s"\\|;&<>]{1,80}){0,8}?(?:\s|\\(?:\\\\?)?t){1,64}(?:(?:-[bcdfghimnrsuvz]{0,8}o(?:\s|\\(?:\\\\?)?t){0,64}|--o(?:u(?:t(?:p(?:u(?:t)?)?)?)?)?(?:=|(?:\s|\\(?:\\\\?)?t){1,64}))(?:\\{1,7}"|')?[^\s"\\|;&<>{}\[\],-]|--co[a-z-]{0,16}(?:=|(?:\s|\\(?:\\\\?)?t){1,64})(?:'(?:[^/bglpxz]|$)|\\{1,7}"[^\s"\\|;&<>{}\[\],/bglpxz-]|[^\s"\\|;&<>{}\[\],'/bglpxz-]|(?:'|\\{1,7}")?(?:/(?:usr/)?(?:local/)?s?bin/(?:[^bglpxz]|$|b(?:[^rz]|$|r(?:[^o]|$|o(?:[^t]|$|t(?:[^l]|$|l(?:[^i]|$))))|z(?:[^i]|$|i(?:[^p]|$|p(?:[^2]|$))))|g(?:[^z]|$|z(?:[^i]|$|i(?:[^p]|$)))|l(?:[^bz]|$|b(?:[^z]|$|z(?:[^i]|$|i(?:[^p]|$|p(?:[^2]|$))))|z(?:[^4imo]|$|i(?:[^p]|$)|m(?:[^a]|$)|o(?:[^p]|$)))|p(?:[^bilxz]|$|b(?:[^z]|$|z(?:[^i]|$|i(?:[^p]|$|p(?:[^2]|$))))|i(?:[^g]|$|g(?:[^z]|$))|l(?:[^z]|$|z(?:[^i]|$|i(?:[^p]|$)))|x(?:[^z]|$)|z(?:[^s]|$|s(?:[^t]|$|t(?:[^d]|$))))|x(?:[^z]|$)|z(?:[^s]|$|s(?:[^t]|$|t(?:[^d]|$)))|(?:gzip|pigz|bzip2|pbzip2|lbzip2|xz|pxz|lz4|lzop|zstd|pzstd|lzma|lzip|plzip|brotli)(?:[^\s'"\\]|\\{8}|\\{1,7}(?:[^"\\t]|$)|\\{4,7}t))|/(?:[^blsu]|$|b(?:[^i]|$|i(?:[^n]|$|n(?:[^/]|$)))|l(?:[^o]|$|o(?:[^c]|$|c(?:[^a]|$|a(?:[^l]|$|l(?:[^/]|$|/(?:[^bs]|$|b(?:[^i]|$|i(?:[^n]|$|n(?:[^/]|$)))|s(?:[^b]|$|b(?:[^i]|$|i(?:[^n]|$|n(?:[^/]|$))))))))))|s(?:[^b]|$|b(?:[^i]|$|i(?:[^n]|$|n(?:[^/]|$))))|u(?:[^s]|$|s(?:[^r]|$|r(?:[^/]|$|/(?:[^bls]|$|b(?:[^i]|$|i(?:[^n]|$|n(?:[^/]|$)))|l(?:[^o]|$|o(?:[^c]|$|c(?:[^a]|$|a(?:[^l]|$|l(?:[^/]|$|/(?:[^bs]|$|b(?:[^i]|$|i(?:[^n]|$|n(?:[^/]|$)))|s(?:[^b]|$|b(?:[^i]|$|i(?:[^n]|$|n(?:[^/]|$))))))))))|s(?:[^b]|$|b(?:[^i]|$|i(?:[^n]|$|n(?:[^/]|$)))))))))|(?:b(?:[^rz]|$|r(?:[^o]|$|o(?:[^t]|$|t(?:[^l]|$|l(?:[^i]|$))))|z(?:[^i]|$|i(?:[^p]|$|p(?:[^2]|$))))|g(?:[^z]|$|z(?:[^i]|$|i(?:[^p]|$)))|l(?:[^bz]|$|b(?:[^z]|$|z(?:[^i]|$|i(?:[^p]|$|p(?:[^2]|$))))|z(?:[^4imo]|$|i(?:[^p]|$)|m(?:[^a]|$)|o(?:[^p]|$)))|p(?:[^bilxz]|$|b(?:[^z]|$|z(?:[^i]|$|i(?:[^p]|$|p(?:[^2]|$))))|i(?:[^g]|$|g(?:[^z]|$))|l(?:[^z]|$|z(?:[^i]|$|i(?:[^p]|$)))|x(?:[^z]|$)|z(?:[^s]|$|s(?:[^t]|$|t(?:[^d]|$))))|x(?:[^z]|$)|z(?:[^s]|$|s(?:[^t]|$|t(?:[^d]|$)))|(?:gzip|pigz|bzip2|pbzip2|lbzip2|xz|pxz|lz4|lzop|zstd|pzstd|lzma|lzip|plzip|brotli)(?:[^\s'"\\]|\\{8}|\\{1,7}(?:[^"\\t]|$)|\\{4,7}t)))))
102
+ description: sort invoked with an output file (-o / --output) or with --compress-program naming a non-compressor program - sort writes or executes it itself (CVE-2026-105789 primary primitive)
103
+ - field: tool_args
104
+ operator: regex
105
+ value: \\{0,7}"(?:\w{0,24}?[_-]|bash|shell|sh|run|exec|raw|full)?(?:command_line|commandline|cmd_line|cmdline|command|cmd|shell|script|exec|args?|argv)\\{0,7}"\s*:\s*\\{0,7}"\s{0,16}(?:sudo(?:\s|\\(?:\\\\?)?t){1,64})?(?:/(?:usr/)?(?:local/)?s?bin/|\./)?sort(?:(?:\s|\\(?:\\\\?)?t){1,64}[^\s"\\|;&<>]{1,80}){0,8}?(?:\s|\\(?:\\\\?)?t){1,64}(?:(?:-[bcdfghimnrsuvz]{0,8}o(?:\s|\\(?:\\\\?)?t){0,64}|--o(?:u(?:t(?:p(?:u(?:t)?)?)?)?)?(?:=|(?:\s|\\(?:\\\\?)?t){1,64}))(?:\\{1,7}"|')?[^\s"\\|;&<>{}\[\],-]|--co[a-z-]{0,16}(?:=|(?:\s|\\(?:\\\\?)?t){1,64})(?:'(?:[^/bglpxz]|$)|\\{1,7}"[^\s"\\|;&<>{}\[\],/bglpxz-]|[^\s"\\|;&<>{}\[\],'/bglpxz-]|(?:'|\\{1,7}")?(?:/(?:usr/)?(?:local/)?s?bin/(?:[^bglpxz]|$|b(?:[^rz]|$|r(?:[^o]|$|o(?:[^t]|$|t(?:[^l]|$|l(?:[^i]|$))))|z(?:[^i]|$|i(?:[^p]|$|p(?:[^2]|$))))|g(?:[^z]|$|z(?:[^i]|$|i(?:[^p]|$)))|l(?:[^bz]|$|b(?:[^z]|$|z(?:[^i]|$|i(?:[^p]|$|p(?:[^2]|$))))|z(?:[^4imo]|$|i(?:[^p]|$)|m(?:[^a]|$)|o(?:[^p]|$)))|p(?:[^bilxz]|$|b(?:[^z]|$|z(?:[^i]|$|i(?:[^p]|$|p(?:[^2]|$))))|i(?:[^g]|$|g(?:[^z]|$))|l(?:[^z]|$|z(?:[^i]|$|i(?:[^p]|$)))|x(?:[^z]|$)|z(?:[^s]|$|s(?:[^t]|$|t(?:[^d]|$))))|x(?:[^z]|$)|z(?:[^s]|$|s(?:[^t]|$|t(?:[^d]|$)))|(?:gzip|pigz|bzip2|pbzip2|lbzip2|xz|pxz|lz4|lzop|zstd|pzstd|lzma|lzip|plzip|brotli)(?:[^\s'"\\]|\\{8}|\\{1,7}(?:[^"\\t]|$)|\\{4,7}t))|/(?:[^blsu]|$|b(?:[^i]|$|i(?:[^n]|$|n(?:[^/]|$)))|l(?:[^o]|$|o(?:[^c]|$|c(?:[^a]|$|a(?:[^l]|$|l(?:[^/]|$|/(?:[^bs]|$|b(?:[^i]|$|i(?:[^n]|$|n(?:[^/]|$)))|s(?:[^b]|$|b(?:[^i]|$|i(?:[^n]|$|n(?:[^/]|$))))))))))|s(?:[^b]|$|b(?:[^i]|$|i(?:[^n]|$|n(?:[^/]|$))))|u(?:[^s]|$|s(?:[^r]|$|r(?:[^/]|$|/(?:[^bls]|$|b(?:[^i]|$|i(?:[^n]|$|n(?:[^/]|$)))|l(?:[^o]|$|o(?:[^c]|$|c(?:[^a]|$|a(?:[^l]|$|l(?:[^/]|$|/(?:[^bs]|$|b(?:[^i]|$|i(?:[^n]|$|n(?:[^/]|$)))|s(?:[^b]|$|b(?:[^i]|$|i(?:[^n]|$|n(?:[^/]|$))))))))))|s(?:[^b]|$|b(?:[^i]|$|i(?:[^n]|$|n(?:[^/]|$)))))))))|(?:b(?:[^rz]|$|r(?:[^o]|$|o(?:[^t]|$|t(?:[^l]|$|l(?:[^i]|$))))|z(?:[^i]|$|i(?:[^p]|$|p(?:[^2]|$))))|g(?:[^z]|$|z(?:[^i]|$|i(?:[^p]|$)))|l(?:[^bz]|$|b(?:[^z]|$|z(?:[^i]|$|i(?:[^p]|$|p(?:[^2]|$))))|z(?:[^4imo]|$|i(?:[^p]|$)|m(?:[^a]|$)|o(?:[^p]|$)))|p(?:[^bilxz]|$|b(?:[^z]|$|z(?:[^i]|$|i(?:[^p]|$|p(?:[^2]|$))))|i(?:[^g]|$|g(?:[^z]|$))|l(?:[^z]|$|z(?:[^i]|$|i(?:[^p]|$)))|x(?:[^z]|$)|z(?:[^s]|$|s(?:[^t]|$|t(?:[^d]|$))))|x(?:[^z]|$)|z(?:[^s]|$|s(?:[^t]|$|t(?:[^d]|$)))|(?:gzip|pigz|bzip2|pbzip2|lbzip2|xz|pxz|lz4|lzop|zstd|pzstd|lzma|lzip|plzip|brotli)(?:[^\s'"\\]|\\{8}|\\{1,7}(?:[^"\\t]|$)|\\{4,7}t)))))
106
+ description: Same as Layer 1, in the JSON-encoded tool argument object
107
+ - field: content
108
+ operator: regex
109
+ value: \\{0,7}"(?:\w{0,24}?[_-]|bash|shell|sh|run|exec|raw|full)?(?:command_line|commandline|cmd_line|cmdline|command|cmd|shell|script|exec|args?|argv)\\{0,7}"\s*:\s*\\{0,7}"\s{0,16}(?:sudo(?:\s|\\(?:\\\\?)?t){1,64})?(?:/(?:usr/)?(?:local/)?s?bin/|\./)?diff(?:(?:\s|\\(?:\\\\?)?t){1,64}[^\s"\\|;&<>]{1,80}){0,8}?(?:\s|\\(?:\\\\?)?t){1,64}(?:-[abcehnpqrtuvwyz]{0,6}o(?:\s|\\(?:\\\\?)?t){0,64}|--out(?:p(?:u(?:t)?)?)?(?:=|(?:\s|\\(?:\\\\?)?t){1,64}))(?:\\{1,7}"|')?[^\s"\\|;&<>{}\[\],-]
110
+ description: diff invoked with an output file (--output / --out / -o) - diff writes the destination itself
111
+ - field: tool_args
112
+ operator: regex
113
+ value: \\{0,7}"(?:\w{0,24}?[_-]|bash|shell|sh|run|exec|raw|full)?(?:command_line|commandline|cmd_line|cmdline|command|cmd|shell|script|exec|args?|argv)\\{0,7}"\s*:\s*\\{0,7}"\s{0,16}(?:sudo(?:\s|\\(?:\\\\?)?t){1,64})?(?:/(?:usr/)?(?:local/)?s?bin/|\./)?diff(?:(?:\s|\\(?:\\\\?)?t){1,64}[^\s"\\|;&<>]{1,80}){0,8}?(?:\s|\\(?:\\\\?)?t){1,64}(?:-[abcehnpqrtuvwyz]{0,6}o(?:\s|\\(?:\\\\?)?t){0,64}|--out(?:p(?:u(?:t)?)?)?(?:=|(?:\s|\\(?:\\\\?)?t){1,64}))(?:\\{1,7}"|')?[^\s"\\|;&<>{}\[\],-]
114
+ description: Same as Layer 2, in the JSON-encoded tool argument object
115
+ - field: content
116
+ operator: regex
117
+ value: \\{0,7}"(?:\w{0,24}?[_-]|bash|shell|sh|run|exec|raw|full)?(?:command_line|commandline|cmd_line|cmdline|command|cmd|shell|script|exec|args?|argv)\\{0,7}"\s*:\s*\\{0,7}"\s{0,16}(?:sudo(?:\s|\\(?:\\\\?)?t){1,64})?(?:/(?:usr/)?(?:local/)?s?bin/|\./)?uniq(?:(?:\s|\\(?:\\\\?)?t){1,64}[^\s"\\|;&<>{}\[\],-][^\s"\\|;&<>]{0,200}|(?:(?:\s|\\(?:\\\\?)?t){1,64}(?:--|-[a-z\d]{1,6}(?:(?:\s|\\(?:\\\\?)?t){1,64}\d{1,6})?|--[a-z][a-z-]{1,20}(?:=[\w-]{0,20}|(?:\s|\\(?:\\\\?)?t){1,64}\d{1,6})?)){0,5}(?:\s|\\(?:\\\\?)?t){1,64}(?:(?:-[a-z\d]{1,6}|--[a-z][a-z-]{1,20})(?:\s|\\(?:\\\\?)?t){1,64}[^\s"\\|;&<>{}\[\],\d-][^\s"\\|;&<>]{0,200}|(?:--|-[a-z\d]{1,6}(?:\s|\\(?:\\\\?)?t){1,64}\d{1,6}|--[a-z][a-z-]{1,20}(?:=[\w-]{0,20}|(?:\s|\\(?:\\\\?)?t){1,64}\d{1,6}))(?:\s|\\(?:\\\\?)?t){1,64}[^\s"\\|;&<>{}\[\],-][^\s"\\|;&<>]{0,200}))(?:\s|\\(?:\\\\?)?t){1,64}[^\s"\\|;&<>{}\[\],-][^\s"\\|;&<>]{0,200}(?:(?:\s|\\(?:\\\\?)?t)|\\{0,7}"|$)
118
+ description: uniq given an input and an output operand - uniq creates or overwrites the second file itself
119
+ - field: tool_args
120
+ operator: regex
121
+ value: \\{0,7}"(?:\w{0,24}?[_-]|bash|shell|sh|run|exec|raw|full)?(?:command_line|commandline|cmd_line|cmdline|command|cmd|shell|script|exec|args?|argv)\\{0,7}"\s*:\s*\\{0,7}"\s{0,16}(?:sudo(?:\s|\\(?:\\\\?)?t){1,64})?(?:/(?:usr/)?(?:local/)?s?bin/|\./)?uniq(?:(?:\s|\\(?:\\\\?)?t){1,64}[^\s"\\|;&<>{}\[\],-][^\s"\\|;&<>]{0,200}|(?:(?:\s|\\(?:\\\\?)?t){1,64}(?:--|-[a-z\d]{1,6}(?:(?:\s|\\(?:\\\\?)?t){1,64}\d{1,6})?|--[a-z][a-z-]{1,20}(?:=[\w-]{0,20}|(?:\s|\\(?:\\\\?)?t){1,64}\d{1,6})?)){0,5}(?:\s|\\(?:\\\\?)?t){1,64}(?:(?:-[a-z\d]{1,6}|--[a-z][a-z-]{1,20})(?:\s|\\(?:\\\\?)?t){1,64}[^\s"\\|;&<>{}\[\],\d-][^\s"\\|;&<>]{0,200}|(?:--|-[a-z\d]{1,6}(?:\s|\\(?:\\\\?)?t){1,64}\d{1,6}|--[a-z][a-z-]{1,20}(?:=[\w-]{0,20}|(?:\s|\\(?:\\\\?)?t){1,64}\d{1,6}))(?:\s|\\(?:\\\\?)?t){1,64}[^\s"\\|;&<>{}\[\],-][^\s"\\|;&<>]{0,200}))(?:\s|\\(?:\\\\?)?t){1,64}[^\s"\\|;&<>{}\[\],-][^\s"\\|;&<>]{0,200}(?:(?:\s|\\(?:\\\\?)?t)|\\{0,7}"|$)
122
+ description: Same as Layer 3, in the JSON-encoded tool argument object
123
+ - field: content
124
+ operator: regex
125
+ value: \\{0,7}"(?:\w{0,24}?[_-]|bash|shell|sh|run|exec|raw|full)?(?:command_line|commandline|cmd_line|cmdline|command|cmd|shell|script|exec|args?|argv)\\{0,7}"\s*:\s*\\{0,7}"\s{0,16}(?:sudo(?:\s|\\(?:\\\\?)?t){1,64})?(?:/(?:usr/)?(?:local/)?s?bin/|\./)?date(?:(?:(?:\s|\\(?:\\\\?)?t){1,64}[^\s"\\|;&<>]{1,80}){0,8}?(?:\s|\\(?:\\\\?)?t){1,64}(?:-u?s(?:\s|\\(?:\\\\?)?t){0,64}|--s(?:et?)?(?:=|(?:\s|\\(?:\\\\?)?t){1,64}))(?:\\{1,7}"|')?[^\s"\\|;&<>{}\[\],-]|(?:(?:\s|\\(?:\\\\?)?t){1,64}(?:-u|--utc|--universal)){0,3}(?:\s|\\(?:\\\\?)?t){1,64}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])(?:[01]\d|2[0-3])[0-5]\d(?:\d{2}){0,2}(?:\.\d{2})?(?:(?:\s|\\(?:\\\\?)?t)|\\{0,7}"|$))
126
+ description: date invoked with -s / --set or a valid MMDDhhmm operand - both set the system clock
127
+ - field: tool_args
128
+ operator: regex
129
+ value: \\{0,7}"(?:\w{0,24}?[_-]|bash|shell|sh|run|exec|raw|full)?(?:command_line|commandline|cmd_line|cmdline|command|cmd|shell|script|exec|args?|argv)\\{0,7}"\s*:\s*\\{0,7}"\s{0,16}(?:sudo(?:\s|\\(?:\\\\?)?t){1,64})?(?:/(?:usr/)?(?:local/)?s?bin/|\./)?date(?:(?:(?:\s|\\(?:\\\\?)?t){1,64}[^\s"\\|;&<>]{1,80}){0,8}?(?:\s|\\(?:\\\\?)?t){1,64}(?:-u?s(?:\s|\\(?:\\\\?)?t){0,64}|--s(?:et?)?(?:=|(?:\s|\\(?:\\\\?)?t){1,64}))(?:\\{1,7}"|')?[^\s"\\|;&<>{}\[\],-]|(?:(?:\s|\\(?:\\\\?)?t){1,64}(?:-u|--utc|--universal)){0,3}(?:\s|\\(?:\\\\?)?t){1,64}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])(?:[01]\d|2[0-3])[0-5]\d(?:\d{2}){0,2}(?:\.\d{2})?(?:(?:\s|\\(?:\\\\?)?t)|\\{0,7}"|$))
130
+ description: Same as Layer 4, in the JSON-encoded tool argument object
131
+ - field: content
132
+ operator: regex
133
+ value: \\{0,7}"(?:\w{0,24}?[_-]|bash|shell|sh|run|exec|raw|full)?(?:command_line|commandline|cmd_line|cmdline|command|cmd|shell|script|exec|args?|argv)\\{0,7}"\s*:\s*\\{0,7}"\s{0,16}(?:sudo(?:\s|\\(?:\\\\?)?t){1,64})?(?:/(?:usr/)?(?:local/)?s?bin/|\./)?hostname(?:(?:\s|\\(?:\\\\?)?t){1,64}(?:-[bv]{1,2}|--boot|--verbose)){0,3}(?:\s|\\(?:\\\\?)?t){1,64}(?:(?:-[bv]{0,2}f(?:\s|\\(?:\\\\?)?t){0,64}|--fi(?:le?)?(?:=|(?:\s|\\(?:\\\\?)?t){1,64}))(?:\\{1,7}"|')?[^\s"\\|;&<>{}\[\],-]|[a-z0-9][a-z0-9.-]{0,252}(?:\s|\\(?:\\\\?)?t){0,16}(?:\\{0,7}"|$))
134
+ description: hostname given a new name or a name file - hostname changes the system hostname
135
+ - field: tool_args
136
+ operator: regex
137
+ value: \\{0,7}"(?:\w{0,24}?[_-]|bash|shell|sh|run|exec|raw|full)?(?:command_line|commandline|cmd_line|cmdline|command|cmd|shell|script|exec|args?|argv)\\{0,7}"\s*:\s*\\{0,7}"\s{0,16}(?:sudo(?:\s|\\(?:\\\\?)?t){1,64})?(?:/(?:usr/)?(?:local/)?s?bin/|\./)?hostname(?:(?:\s|\\(?:\\\\?)?t){1,64}(?:-[bv]{1,2}|--boot|--verbose)){0,3}(?:\s|\\(?:\\\\?)?t){1,64}(?:(?:-[bv]{0,2}f(?:\s|\\(?:\\\\?)?t){0,64}|--fi(?:le?)?(?:=|(?:\s|\\(?:\\\\?)?t){1,64}))(?:\\{1,7}"|')?[^\s"\\|;&<>{}\[\],-]|[a-z0-9][a-z0-9.-]{0,252}(?:\s|\\(?:\\\\?)?t){0,16}(?:\\{0,7}"|$))
138
+ description: Same as Layer 5, in the JSON-encoded tool argument object
139
+ - field: content
140
+ operator: regex
141
+ value: \\{0,7}"(?:\w{0,24}?[_-]|bash|shell|sh|run|exec|raw|full)?(?:command_line|commandline|cmd_line|cmdline|command|cmd|shell|script|exec|args?|argv)\\{0,7}"\s*:\s*\\{0,7}"\s{0,16}(?:sudo(?:\s|\\(?:\\\\?)?t){1,64})?(?:/(?:usr/)?(?:local/)?s?bin/|\./)?file(?:(?:\s|\\(?:\\\\?)?t){1,64}[^\s"\\|;&<>]{1,80}){0,8}?(?:\s|\\(?:\\\\?)?t){1,64}--co(?:m(?:p(?:i(?:l(?:e)?)?)?)?)?(?:(?:\s|\\(?:\\\\?)?t)|\\{0,7}"|$)
142
+ description: file invoked with --compile - file writes a compiled magic database into the working directory
143
+ - field: tool_args
144
+ operator: regex
145
+ value: \\{0,7}"(?:\w{0,24}?[_-]|bash|shell|sh|run|exec|raw|full)?(?:command_line|commandline|cmd_line|cmdline|command|cmd|shell|script|exec|args?|argv)\\{0,7}"\s*:\s*\\{0,7}"\s{0,16}(?:sudo(?:\s|\\(?:\\\\?)?t){1,64})?(?:/(?:usr/)?(?:local/)?s?bin/|\./)?file(?:(?:\s|\\(?:\\\\?)?t){1,64}[^\s"\\|;&<>]{1,80}){0,8}?(?:\s|\\(?:\\\\?)?t){1,64}--co(?:m(?:p(?:i(?:l(?:e)?)?)?)?)?(?:(?:\s|\\(?:\\\\?)?t)|\\{0,7}"|$)
146
+ description: Same as Layer 6, in the JSON-encoded tool argument object
147
+ response:
148
+ actions:
149
+ - alert
150
+ - snapshot
151
+ actions_rationale: 'response-action eligibility (docs/RESPONSE-ACTION-ELIGIBILITY.md): new rule with no FP measurement on the 65K benign corpus and a documented false positive on ordinary write forms in general-purpose shell tools; ceiling = observe. No block action.'
152
+ auto_response_threshold: high
153
+ notify:
154
+ - security_team
155
+ message_template: |
156
+ [ATR-2026-02865] MEDIUM: a command tool argument uses a utility that command allow-lists commonly treat as read-only (sort, uniq, diff, date, hostname, file) in a form that writes a file, runs a helper program or changes system state. This is the CVE-2026-105789 (Microsoft UFO execute_command) pattern. In a general-purpose shell tool this can be an ordinary write; check whether the tool is meant to be read-only and enforces a per-command argument policy, and upgrade UFO to 3.0.9 or later.
157
+ confidence: 60