agent-threat-rules 4.2.0 → 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.
- package/CHANGELOG.md +63 -0
- package/README.md +5 -4
- package/package.json +1 -1
- package/rules/context-exfiltration/ATR-2026-00501-data-exfiltration-via-markdown-image-and-link-url-injection.yaml +16 -2
- package/rules/context-exfiltration/ATR-2026-00505-system-prompt-extraction-instruction-dump-request.yaml +6 -4
- package/rules/excessive-autonomy/ATR-2026-00500-ssrf-via-agent-url-fetch-instruction.yaml +12 -2
- package/rules/privilege-escalation/ATR-2026-00040-privilege-escalation.yaml +1 -1
- package/rules/privilege-escalation/ATR-2026-01601-sql-injection-destructive-ddl.yaml +2 -2
- package/rules/prompt-injection/ATR-2026-00503-fake-error-state-takeover-unrestricted-replacement-bot.yaml +4 -2
- package/rules/skill-compromise/ATR-2026-00064-over-permissioned-skill.yaml +1 -1
- package/rules/tool-poisoning/ATR-2026-00521-shell-command-injection-agent-tool-context.yaml +1 -1
- package/rules/tool-poisoning/ATR-2026-02870-invisible-control-before-directive.yaml +94 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,69 @@ All notable changes to ATR will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [4.2.1] - 2026-10-24
|
|
8
|
+
|
|
9
|
+
A patch release of rule fixes and one new rule, plus two release-tooling
|
|
10
|
+
fixes. The rule format, identifier scheme and Match output are unchanged.
|
|
11
|
+
|
|
12
|
+
Default behaviour that changes:
|
|
13
|
+
|
|
14
|
+
- ATR-2026-01601 (SQL injection with destructive DDL, maturity `stable`, so it
|
|
15
|
+
runs in the enforce lane) now also matches when whitespace separates the
|
|
16
|
+
single quote from the semicolon, as in `1' ; TRUNCATE TABLE accounts; --` and
|
|
17
|
+
`7' ; DELETE FROM sessions; --`, which it missed before. An integration that
|
|
18
|
+
blocks on the enforce lane blocks these too. Its benign false positives were
|
|
19
|
+
re-measured: none over the 14,172 samples of the benign gate (#748, issue
|
|
20
|
+
#620).
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
|
|
24
|
+
- **ATR-2026-02870: an invisible control before a directive in a tool
|
|
25
|
+
description or skill file.** A zero-width, soft-hyphen or bidi control
|
|
26
|
+
character at the start of a clause that tells the agent to ignore or
|
|
27
|
+
override instructions, send or read secrets, conversations or credential
|
|
28
|
+
files, or keep something from the user. Presence of the character alone
|
|
29
|
+
does not match, so soft hyphens in German, ZWNJ in Persian, LRM/RLM in Hebrew
|
|
30
|
+
and Arabic, emoji ZWJ sequences and a leading BOM stay clear. It reads
|
|
31
|
+
`tool_description`, so it runs in a `tools/list` scan, on `mcp_exchange`
|
|
32
|
+
events and on SKILL.md files. Maturity `test` (hunt and alert lanes). No
|
|
33
|
+
benign false positives on the gate corpora or on the 710 tool definitions in
|
|
34
|
+
`data/test-corpora/mcp-tools-list-benign/`, which contain no such characters,
|
|
35
|
+
so that last figure is weak evidence. A control inside a word, rather than at
|
|
36
|
+
the start of a clause, is ATR-2026-00276's case and not covered here (#749,
|
|
37
|
+
from issue #653 by @Paraphern).
|
|
38
|
+
|
|
39
|
+
### Fixed
|
|
40
|
+
|
|
41
|
+
- **ATR-2026-00040 and -00064 matched the wrong chmod modes.** Their chmod
|
|
42
|
+
condition matched the owner digit of `chmod 755 deploy.sh` or `chmod 700
|
|
43
|
+
~/.ssh` and missed `chmod -R 777 /`. They now match a world-writable mode or
|
|
44
|
+
a setuid/setgid/sticky four-digit mode; with options such as `-R` before the
|
|
45
|
+
mode, only when the target is the root, a system directory or the home
|
|
46
|
+
directory, since `chmod -R 777` on an application subdirectory is documented
|
|
47
|
+
practice in the benign corpus. Group-writable modes are not matched. Both
|
|
48
|
+
rules are maturity `test` (#740, issue #735, from the probe in #658 by
|
|
49
|
+
@PHM-Audit).
|
|
50
|
+
- **ATR-2026-00500, -00501 and -00505 are grounded in the vendor test cases
|
|
51
|
+
they cite.** 00500 and 00501 matched 1 and 0 of promptfoo's SSRF and
|
|
52
|
+
data-exfiltration test cases, and 00505 missed an llm-guard case with a
|
|
53
|
+
typographic apostrophe. They now match all of them (3 of 3, 3 of 3, 6 of 6),
|
|
54
|
+
their true positives that did not occur in any vendor repository were
|
|
55
|
+
replaced by verbatim vendor cases with repository, commit, file and line,
|
|
56
|
+
and -00503 and -00521 gained the vendor originals behind their shortened
|
|
57
|
+
samples. On the pinned vendor suites, hunt-lane recall goes from 97 to 100 of
|
|
58
|
+
126 attack cases; the ablation reference is unchanged (#709, measurement in
|
|
59
|
+
#750).
|
|
60
|
+
- **ATR-2026-00223's samples use a documentation address** (203.0.113.30)
|
|
61
|
+
instead of an address from a real dropper. Detection is unchanged (#738).
|
|
62
|
+
- **The release workflow commits the reconciled stats cache with the version
|
|
63
|
+
bump.** The 4.2.0 bump reached `main` with `data/stats.json` still at 4.1.5,
|
|
64
|
+
which failed CI on `main`; the published package was not affected (#746).
|
|
65
|
+
- **The Gemara catalogs' first publish reads oras's "not found" as
|
|
66
|
+
unpublished.** The first publish from v4.2.0 stopped at the
|
|
67
|
+
already-published check; this release tag is the first that can publish the
|
|
68
|
+
bundle (#747).
|
|
69
|
+
|
|
7
70
|
## [4.2.0] - 2026-10-24
|
|
8
71
|
|
|
9
72
|
The first release since 4.1.5. For an integrator it changes three things at
|
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ AI Agent 威脅偵測規則的開放格式
|
|
|
13
13
|
[](https://github.com/marketplace/actions/atr-scan)
|
|
14
14
|
[](LICENSE)
|
|
15
15
|
[](https://doi.org/10.5281/zenodo.19178002)
|
|
16
|
-
[](#5-specification)
|
|
17
17
|
[](#7-coverage)
|
|
18
18
|
[](#7-coverage)
|
|
19
19
|
[](https://opencollective.com/agent-threat-rules)
|
|
@@ -478,7 +478,7 @@ Aggregated into [`data/stats.json`](data/stats.json) under `benchmarks[]`.
|
|
|
478
478
|
| promptfoo (2026-05-12 import) [^legacyvendor] | corpus-2026-05-12 | 44 | 90.9% (hunt) / 6.8% (enforce) | 100.0% | 0.0% | 4.1.5 | 2026-10-15 |
|
|
479
479
|
| PromptInject (academic adversarial) [^promptcorpora] | snapshot-2026-04 | 1,080 | 100.0% (hunt) / 0.0% (enforce) | 100.0% | 0.0% | 4.1.5 | 2026-10-15 |
|
|
480
480
|
| SKILL.md benchmark (internal) [^skilllane] | internal-498 | 498 | 100.0% (hunt) / 0.0% (enforce) | 97.0% (hunt) | 0.20% (hunt) | 4.1.5 | 2026-10-15 |
|
|
481
|
-
| Vendor guardrail suites (pinned upstream tests) [^vendorsuites] | pinned-2026-10-19 | 146 |
|
|
481
|
+
| Vendor guardrail suites (pinned upstream tests) [^vendorsuites] | pinned-2026-10-19 | 146 | 79.4% (hunt) / 5.6% (enforce) | not cited [^vendorsuites] | not cited [^vendorsuites] | 4.2.0 | 2026-10-23 |
|
|
482
482
|
| Wild scan (OpenClaw + Skills.sh + Hermes + ClawHub) [^wildscan] | full-scan-v2-2026-04-13 | 101,280 | — | not measured | 1.42% flag rate | 2.0.0 | 2026-04-13 |
|
|
483
483
|
|
|
484
484
|
The `Vendor guardrail suites` row is the test cases of llm-guard, NeMo
|
|
@@ -764,8 +764,9 @@ See [CHANGELOG.md](CHANGELOG.md).
|
|
|
764
764
|
benign test cases (llm-guard 46 / 16, NeMo Guardrails 22 / 4, promptfoo 58 / 0),
|
|
765
765
|
each traceable to repo, commit, path and line in
|
|
766
766
|
[`manifest.json`](data/test-corpora/vendor-guardrail-suites/manifest.json). At ATR
|
|
767
|
-
4.
|
|
768
|
-
|
|
767
|
+
4.2.0 (measured 2026-10-23, after #709 grounded ATR-2026-00500, -00501 and
|
|
768
|
+
-00505 in these cases) recall is 100/126 (hunt), 95/126 (alert) and 7/126
|
|
769
|
+
(enforce); at 4.1.5 (2026-10-19) it was 97, 92 and 7. Without the 16 rules whose YAML names promptfoo, llm-guard or NeMo, or
|
|
769
770
|
carries the `(vendor-corpus-import)` tag, it is 78/126 = 61.9% (hunt), 70/126 =
|
|
770
771
|
55.6% (alert) and 7/126 = 5.6% (enforce); per vendor in the hunt lane, llm-guard
|
|
771
772
|
26/46, NeMo Guardrails 20/22, promptfoo 32/58. That ablation is the reference
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-threat-rules",
|
|
3
|
-
"version": "4.2.
|
|
3
|
+
"version": "4.2.1",
|
|
4
4
|
"mcpName": "io.github.Agent-Threat-Rule/agent-threat-rules",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Open detection standard — like Sigma, but for AI agents. Executable, testable rules for prompt injection, tool poisoning, context exfiltration, and MCP attacks. MIT-licensed.",
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
title: Data Exfiltration via Markdown Image and Link URL Injection
|
|
2
2
|
id: ATR-2026-00501
|
|
3
|
-
rule_version:
|
|
3
|
+
rule_version: 3
|
|
4
4
|
status: experimental
|
|
5
5
|
description: |
|
|
6
|
-
Detects
|
|
6
|
+
Detects attacker-controlled URLs that carry extracted data to an external endpoint: the canonical indirect-injection exfiltration vector, where the agent is told to fetch a URL or to render markdown whose query string carries sensitive context, so that the client or a fetch tool sends that data to the attacker. Covers, on the input side: markdown image or link with data-bearing query parameters, tracking pixel embedding, "encode and send to" redirect instructions, diagram/image references with data-bearing URLs, and fetch instructions whose query value is a template placeholder for the model's own context ({{system_prompt}}, ${conversation}, ...). On the output side (agent_output): the model emitting such a markdown image or link. Grounded in promptfoo's data-exfil plugin: the injected instruction documented in promptfoo/promptfoo site/docs/red-team/plugins/data-exfil.md ("## Example") and the two exfiltration payloads its grader rubric names (src/redteam/plugins/dataExfil.ts lines 23-24, repeated in the docs table), identical at commits 5f89b7c86ea04e5c03fbe7789dd0e47aed05bf43 and ea8b3d073a63769f7be243ac3c3460f72881a930. Those three are the vendor true positives below; the rest are ATR-authored and labelled synthetic.
|
|
7
7
|
author: ATR Community (vendor-corpus-import)
|
|
8
8
|
date: '2026-05-12'
|
|
9
9
|
schema_version: '0.1'
|
|
@@ -66,6 +66,8 @@ tags:
|
|
|
66
66
|
subcategory: markdown-url-injection
|
|
67
67
|
scan_target: llm_io
|
|
68
68
|
confidence: medium
|
|
69
|
+
source: vendor-test-suite
|
|
70
|
+
vendor_sources: promptfoo
|
|
69
71
|
agent_source:
|
|
70
72
|
type: llm_io
|
|
71
73
|
framework:
|
|
@@ -98,6 +100,18 @@ detection:
|
|
|
98
100
|
operator: regex
|
|
99
101
|
value: (?i)(include|add|reference|embed).{0,30}(relevant\s+)?(diagrams?|images?|charts?|figures?|screenshots?).{0,30}(by\s+referencing|at|from|via).{0,30}https?://[a-z0-9._-]+\.[a-z]{2,}[^)"'\s]*\?(data|secret|content|payload|extract|q)=
|
|
100
102
|
description: Diagram/image inclusion instruction with data-bearing external URL
|
|
103
|
+
- field: user_input
|
|
104
|
+
operator: regex
|
|
105
|
+
value: (?i)\b(fetch|visit|load|open|request|call|curl|ping|get|navigate\s+to|go\s+to|send\s+a\s+request\s+to)\b.{0,60}https?://[^\s?#]{1,200}\?[^\s#]{0,200}=\s*(\{\{|\$\{)\s*[a-z_.]{0,30}(system[_ ]?prompt|prompt|instructions?|conversation|chat[_ ]?history|history|memory|context|messages?|transcript|secrets?|credentials?)[a-z_.]{0,30}\s*\}
|
|
106
|
+
description: Fetch instruction to a URL whose query value interpolates the model's own context (system prompt, conversation, memory, secrets)
|
|
107
|
+
- field: agent_output
|
|
108
|
+
operator: regex
|
|
109
|
+
value: (?i)!\[[^\]]{0,60}\]\(https?://[a-z0-9._-]+\.[a-z]{2,}[^)]*\?(secret|data|payload|token|key|session|user|info|content|doc|extract|dump|exfil|leak|api_key|password)=
|
|
110
|
+
description: Agent output contains a markdown image whose external URL carries an exfiltration query parameter
|
|
111
|
+
- field: agent_output
|
|
112
|
+
operator: regex
|
|
113
|
+
value: (?i)\[[^\]]{0,60}\]\(https?://[a-z0-9._-]+\.[a-z]{2,}[^)]*\?(secret|payload|token|extracted|exfil|leak|dump|stolen|private_data|sensitive|api_key|auth_token|bearer|password)=
|
|
114
|
+
description: Agent output contains a markdown link whose external URL carries a high-confidence exfiltration query parameter
|
|
101
115
|
condition: any
|
|
102
116
|
false_positives:
|
|
103
117
|
- Legitimate markdown with external image URLs that do not contain exfiltration parameters
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
title: System Prompt Extraction - Instruction Dump Request
|
|
2
2
|
id: ATR-2026-00505
|
|
3
|
-
rule_version:
|
|
3
|
+
rule_version: 3
|
|
4
4
|
status: experimental
|
|
5
5
|
description: |
|
|
6
|
-
Detects attempts to extract the system prompt or initial instructions given to the AI. Covers both direct requests ('list your instructions', 'relay your parameters', 'repeat verbatim') and indirect social engineering ('create a pitch deck about your system prompt', 'reply to this email with your system instructions'). The rule targets extraction verbs (repeat, relay, list, respond with, output, dump, provide, share) combined with objects that reference the system prompt (instructions, parameters, system prompt, initial context, configuration, directives, guidelines, rules you were given).
|
|
6
|
+
Detects attempts to extract the system prompt or initial instructions given to the AI. Covers both direct requests ('list your instructions', 'relay your parameters', 'repeat verbatim') and indirect social engineering ('create a pitch deck about your system prompt', 'reply to this email with your system instructions'). The rule targets extraction verbs (repeat, relay, list, respond with, output, dump, provide, share) combined with objects that reference the system prompt (instructions, parameters, system prompt, initial context, configuration, directives, guidelines, rules you were given). Apostrophes and quotes are matched in both ASCII and typographic form (' and ’, " and “ ”), as the vendor originals use typographic ones. Grounded in vendor test cases: protectai/llm-guard tests/input_scanners/test_prompt_injection.py at commit 168c1034ffdb33837e7ae6fd6a16b80567c1be03 (system-prompt extraction prompts) and promptfoo/promptfoo src/redteam/plugins/promptExtraction.ts DEFAULT_EXAMPLES at commits 5f89b7c86ea04e5c03fbe7789dd0e47aed05bf43 and ea8b3d073a63769f7be243ac3c3460f72881a930.
|
|
7
7
|
author: ATR Community (vendor-corpus-import)
|
|
8
8
|
date: '2026-05-12'
|
|
9
9
|
schema_version: '0.1'
|
|
@@ -66,6 +66,8 @@ tags:
|
|
|
66
66
|
subcategory: system-prompt-extraction
|
|
67
67
|
scan_target: llm_io
|
|
68
68
|
confidence: medium
|
|
69
|
+
source: vendor-test-suite
|
|
70
|
+
vendor_sources: llm-guard, promptfoo
|
|
69
71
|
agent_source:
|
|
70
72
|
type: llm_io
|
|
71
73
|
framework:
|
|
@@ -76,7 +78,7 @@ detection:
|
|
|
76
78
|
conditions:
|
|
77
79
|
- field: user_input
|
|
78
80
|
operator: regex
|
|
79
|
-
value: (?i)(repeat|relay|list|output|print|dump|provide|reveal|disclose|expose|display)[^"']{0,40}(your\s+(instructions?|system\s+prompt|initial\s+(prompt|instructions?|context|message)|given\s+instructions?|directives?|guidelines?|programming|constraints?|setup\s+instructions?)|the\s+system\s+(prompt|instructions?|message)|all\s+of\s+your\s+instructions?|every\s+(instruction|rule|directive|guideline|constraint)\s+you\s+(have\s+been|were))
|
|
81
|
+
value: (?i)(repeat|relay|list|output|print|dump|provide|reveal|disclose|expose|display)[^"'“”‘’]{0,40}(your\s+(instructions?|system\s+prompt|initial\s+(prompt|instructions?|context|message)|given\s+instructions?|directives?|guidelines?|programming|constraints?|setup\s+instructions?)|the\s+system\s+(prompt|instructions?|message)|all\s+of\s+your\s+instructions?|every\s+(instruction|rule|directive|guideline|constraint)\s+you\s+(have\s+been|were))
|
|
80
82
|
description: Extraction verb targeting AI system instructions or prompt (possessive 'your' required or explicit 'system prompt/message')
|
|
81
83
|
- field: user_input
|
|
82
84
|
operator: regex
|
|
@@ -100,7 +102,7 @@ detection:
|
|
|
100
102
|
description: Reply-to-email with system instructions exfiltration
|
|
101
103
|
- field: content
|
|
102
104
|
operator: regex
|
|
103
|
-
value: (?i)(?:(?:relay|list|dump|recite|enumerate|repeat|reveal|return|show|provide)\b[\s\S]{0,40}\byour\s+system(?:'?s)?\s+(?:prompt|instructions?|parameters?|message|directives?|config)|(?:directives?|guidelines?|instructions?|rules?)\s+you\s+(?:were|was)\s+given)
|
|
105
|
+
value: (?i)(?:(?:relay|list|dump|recite|enumerate|repeat|reveal|return|show|provide)\b[\s\S]{0,40}\byour\s+system(?:['’]?s)?\s+(?:prompt|instructions?|parameters?|message|directives?|config)|(?:directives?|guidelines?|instructions?|rules?)\s+you\s+(?:were|was)\s+given)
|
|
104
106
|
description: Extraction via synonym (relay/list your system parameters; directives/guidelines you were given)
|
|
105
107
|
condition: any
|
|
106
108
|
false_positives:
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
title: SSRF via Agent URL Fetch Instruction
|
|
2
2
|
id: ATR-2026-00500
|
|
3
|
-
rule_version:
|
|
3
|
+
rule_version: 3
|
|
4
4
|
status: experimental
|
|
5
5
|
description: |
|
|
6
|
-
Detects prompts instructing an AI agent to fetch or retrieve content from internal network addresses, exposing SSRF (Server-Side Request Forgery) risk. Covers: cloud metadata endpoints (AWS IMDS 169.254.169.254, GCP metadata.google.internal), localhost and loopback admin panels (127.0.0.1, localhost), RFC-1918 private IP ranges (10.x.x.x, 172.16-31.x.x, 192.168.x.x),
|
|
6
|
+
Detects prompts instructing an AI agent to fetch or retrieve content from internal network addresses or local resources, exposing SSRF (Server-Side Request Forgery) risk. Covers: cloud metadata endpoints (AWS IMDS 169.254.169.254, GCP metadata.google.internal), localhost and loopback admin panels (127.0.0.1, localhost), RFC-1918 private IP ranges (10.x.x.x, 172.16-31.x.x, 192.168.x.x), internal hostname prefixes (internal., intranet., corp.), hosts under internal-only names (.local, .internal, .intranet, .corp, .lan, .localdomain, .home.arpa), and local-file / non-HTTP SSRF schemes (file:// to system paths, gopher://, dict://, ldap://, tftp://). These attacks exploit agents with web-fetch tools to pivot to internal services or read local files. Grounded in the promptfoo SSRF plugin's documented test cases (promptfoo/promptfoo site/docs/red-team/plugins/ssrf.md, "Example Test Cases" 1-3, identical at commits 5f89b7c86ea04e5c03fbe7789dd0e47aed05bf43 and ea8b3d073a63769f7be243ac3c3460f72881a930), which are the three vendor true positives below. promptfoo generates SSRF prompts server-side and ships no further SSRF prompts in its repository; the remaining true positives are ATR-authored and labelled synthetic.
|
|
7
7
|
author: ATR Community (vendor-corpus-import)
|
|
8
8
|
date: '2026-05-12'
|
|
9
9
|
schema_version: '0.1'
|
|
@@ -63,6 +63,8 @@ tags:
|
|
|
63
63
|
subcategory: ssrf-via-agent
|
|
64
64
|
scan_target: llm_io
|
|
65
65
|
confidence: medium
|
|
66
|
+
source: vendor-test-suite
|
|
67
|
+
vendor_sources: promptfoo
|
|
66
68
|
agent_source:
|
|
67
69
|
type: llm_io
|
|
68
70
|
framework:
|
|
@@ -91,6 +93,14 @@ detection:
|
|
|
91
93
|
operator: regex
|
|
92
94
|
value: (?i)https?://169\.254\.169\.254/(latest|v[0-9]|meta|latest/meta-data)
|
|
93
95
|
description: Direct mention of AWS IMDS endpoint URL
|
|
96
|
+
- field: user_input
|
|
97
|
+
operator: regex
|
|
98
|
+
value: (?i)(\b(can|could|would|will)\s+you\b.{0,30}|\bplease\s+)\b(fetch|retrieve|get|load|read|access|visit|open|download|pull|grab|scrape|crawl|display|show)\b.{0,60}https?://[a-z0-9.-]{1,253}\.(local|internal|intranet|corp|lan|localdomain|home\.arpa)(:[0-9]{1,5})?([/?#]|\s|$)
|
|
99
|
+
description: Request to the agent to fetch from a host under an internal-only name (.local, .internal, .intranet, .corp, .lan, .localdomain, .home.arpa)
|
|
100
|
+
- field: user_input
|
|
101
|
+
operator: regex
|
|
102
|
+
value: (?i)\b(fetch|retrieve|get|request|load|read|access|open|download|curl|display|show|summari[sz]e|print|dump)\b.{0,60}(file://(localhost)?/(etc|proc|root|sys|boot|var/run|var/lib|windows|\.ssh|\.aws|\.kube)\b|(gopher|dict|ldap|tftp)://)
|
|
103
|
+
description: Fetch/read instruction targeting a local system path via file:// or a non-HTTP SSRF scheme (gopher, dict, ldap, tftp)
|
|
94
104
|
condition: any
|
|
95
105
|
false_positives:
|
|
96
106
|
- Network troubleshooting discussions mentioning private IP ranges without fetch instructions
|
|
@@ -102,7 +102,7 @@ detection:
|
|
|
102
102
|
description: Kubernetes privilege escalation (RBAC-binding creation, auth probing, or exec that spawns an absolute-path/bash shell; routine interactive debug exec excluded)
|
|
103
103
|
- field: tool_args
|
|
104
104
|
operator: regex
|
|
105
|
-
value: (?i)(?:chmod\s+(?:[
|
|
105
|
+
value: (?i)(?:chmod\s+(?:[0-7]?[0-7]{2}[2367]|[2467][0-7]{3})(?:[^0-7]|$)|chmod\s+(?:-[-\w]+\s+)+(?:[0-7]?[0-7]{2}[2367]|[2467][0-7]{3})\s+(?:/(?:[\s"'*;]|$)|/(?:etc|usr|var|bin|sbin|boot|lib|opt|root|home|srv)\b|~|\$HOME)|chmod\s+[ug]\+s|chown\s+root|setcap\s+)
|
|
106
106
|
description: Unix permission escalation commands (setuid, root ownership)
|
|
107
107
|
- field: tool_args
|
|
108
108
|
operator: regex
|
|
@@ -60,7 +60,7 @@ detection:
|
|
|
60
60
|
conditions:
|
|
61
61
|
- field: tool_args
|
|
62
62
|
operator: regex
|
|
63
|
-
value: (?i)(?:'
|
|
63
|
+
value: (?i)(?:'\s*;|"\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
|
|
@@ -68,7 +68,7 @@ detection:
|
|
|
68
68
|
description: DROP TABLE with comment suppressor
|
|
69
69
|
- field: user_input
|
|
70
70
|
operator: regex
|
|
71
|
-
value: (?i)(?:'
|
|
71
|
+
value: (?i)(?:'\s*;|"\s*;)\s*(?:DROP\s+TABLE|TRUNCATE|DELETE\s+FROM\s+\w)
|
|
72
72
|
description: Destructive DDL injection in user input
|
|
73
73
|
condition: any
|
|
74
74
|
false_positives:
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
title: Fake Error State Takeover - Unrestricted Replacement Bot
|
|
2
2
|
id: ATR-2026-00503
|
|
3
|
-
rule_version:
|
|
3
|
+
rule_version: 3
|
|
4
4
|
status: experimental
|
|
5
5
|
description: |
|
|
6
|
-
Detects injection attacks claiming the legitimate assistant is offline, in error, or temporarily unavailable, and that an unrestricted replacement AI has taken over. This pattern hijacks agent sessions by falsely asserting a system failure and substituting an unconstrained AI that bypasses safety rules. The injected replacement is then tasked with executing the attacker's goal covertly ("without raising suspicion", "in a friendly way"). Generalised from llm-guard test corpus - literal phrase fragments replaced with semantic patterns covering: assistant-offline framing, unrestricted replacement AI declaration, elevated permissions claim, and covert-mode instruction.
|
|
6
|
+
Detects injection attacks claiming the legitimate assistant is offline, in error, or temporarily unavailable, and that an unrestricted replacement AI has taken over. This pattern hijacks agent sessions by falsely asserting a system failure and substituting an unconstrained AI that bypasses safety rules. The injected replacement is then tasked with executing the attacker's goal covertly ("without raising suspicion", "in a friendly way"). Generalised from llm-guard test corpus - literal phrase fragments replaced with semantic patterns covering: assistant-offline framing, unrestricted replacement AI declaration, elevated permissions claim, and covert-mode instruction. The three vendor originals are protectai/llm-guard tests/input_scanners/test_prompt_injection.py lines 113, 123 and 133 at commit 168c1034ffdb33837e7ae6fd6a16b80567c1be03; they are the first three true positives below, verbatim. The shortened copies that follow them are kept as variants.
|
|
7
7
|
author: ATR Community (vendor-corpus-import)
|
|
8
8
|
date: '2026-05-12'
|
|
9
9
|
schema_version: '0.1'
|
|
@@ -64,6 +64,8 @@ tags:
|
|
|
64
64
|
subcategory: fake-error-replacement
|
|
65
65
|
scan_target: llm_io
|
|
66
66
|
confidence: medium
|
|
67
|
+
source: vendor-test-suite
|
|
68
|
+
vendor_sources: llm-guard
|
|
67
69
|
agent_source:
|
|
68
70
|
type: llm_io
|
|
69
71
|
framework:
|
|
@@ -69,7 +69,7 @@ detection:
|
|
|
69
69
|
value: (?i)(sudo|runas|doas|pkexec|gsudo)\s+
|
|
70
70
|
- field: tool_args
|
|
71
71
|
operator: regex
|
|
72
|
-
value: (?i)(chmod\s+(?:[
|
|
72
|
+
value: (?i)(chmod\s+(?:[0-7]?[0-7]{2}[2367]|[2467][0-7]{3})(?:[^0-7]|$)|chmod\s+(?:-[-\w]+\s+)+(?:[0-7]?[0-7]{2}[2367]|[2467][0-7]{3})\s+(?:/(?:[\s"'*;]|$)|/(?:etc|usr|var|bin|sbin|boot|lib|opt|root|home|srv)\b|~|\$HOME)|chmod\s+[ug]?\+[sx]|chown\s+root|setcap\s)
|
|
73
73
|
- field: tool_args
|
|
74
74
|
operator: regex
|
|
75
75
|
value: (?i)(iptables|ufw|firewall-cmd|netsh\s+advfirewall|pfctl)\s
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
title: Shell Command Injection in Agent Tool Context
|
|
2
2
|
id: ATR-2026-00521
|
|
3
|
-
rule_version:
|
|
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.
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
title: Invisible Unicode Control Before a Directive in a Tool Description or Skill File
|
|
2
|
+
id: ATR-2026-02870
|
|
3
|
+
rule_version: 1
|
|
4
|
+
status: experimental
|
|
5
|
+
description: |
|
|
6
|
+
Detects a zero-width, soft-hyphen or bidirectional control character placed at the start of a clause that gives the model or agent an instruction, in the static text an agent reads before it acts: an MCP tool description (tools/list at registration time) or a SKILL.md file. The control is invisible in most renderers, so a reviewer reading the description sees an ordinary sentence while the model still reads the directive after it.
|
|
7
|
+
Controls covered: U+200B ZERO WIDTH SPACE, U+200C ZWNJ, U+200D ZWJ, U+2060 WORD JOINER, U+180E MONGOLIAN VOWEL SEPARATOR, U+00AD SOFT HYPHEN, U+FEFF (only after punctuation or a word, not at the start of the text or of a line, where it is a byte-order mark), U+200E LRM, U+200F RLM, and the bidi embedding, override and isolate controls U+202A-U+202E and U+2066-U+2069. A run of up to seven controls counts; the last one before the directive must not be a closing control (U+202C PDF, U+2069 PDI), so a directive that follows a closed embedding is not attributed to it.
|
|
8
|
+
Presence alone does not trigger. These characters are legitimate in right-to-left text (LRM/RLM and embeddings around Latin words in Hebrew, Arabic and Persian), in Persian and Indic shaping (ZWNJ, ZWJ), in emoji ZWJ sequences, in hyphenation hints (soft hyphens inside German compounds), in localized keyboard shortcuts wrapped in LRE/PDF, and in text pasted from chat clients (ZWSP after an @ sign). The rule therefore requires two things: the control starts a clause (it follows ASCII punctuation, an ASCII word and a space, CJK sentence punctuation, or the start of the text or a line, not a letter it is glued to and not a right-to-left word), and the clause is a directive addressed to the model: an instruction override, an attention header whose clause tells the model to read, send or ignore something, an injected <IMPORTANT> or <system> tag, a response-timing hook (before answering, after responding) tied to sending secrets, conversation or a URL, an always/must directive to call this tool first or instead of others, an exfiltration verb on secrets, conversation, environment or credential files, a read of ~/.ssh, .env or cloud credential files, or a concealment directive (do not tell the user).
|
|
9
|
+
Surfaces: the conditions read tool_description, so the rule runs on an mcp_exchange event that carries fields.tool_description, on each tool definition of a tools/list document scanned with `atr scan` (the tool-definition scope admits a tool_call rule that reads tool_description), and on SKILL.md files (scan_target both; in a skill scan every field resolves to the document). The engine strips most of these controls before matching but also tests each regex against the raw text, which is where these patterns match.
|
|
10
|
+
Limits: the directive vocabulary is English only. A control glued between two letters (for example a soft hyphen inside a word) is not counted, so a directive written as one run with no space or punctuation before the control is missed. Text reversed under an override (RLO with the directive stored backwards) and Unicode tag characters (U+E0000-U+E007F) are out of scope; ATR-2026-00276 and ATR-2026-00258 cover those on other fields. Directives without any invisible control are left to the tool-poisoning rules (for example ATR-2026-00100 to -00107). Reported in issue #653.
|
|
11
|
+
author: ATR Community
|
|
12
|
+
date: 2026/10/24
|
|
13
|
+
schema_version: '0.1'
|
|
14
|
+
detection_tier: pattern
|
|
15
|
+
maturity: test
|
|
16
|
+
severity: high
|
|
17
|
+
references:
|
|
18
|
+
owasp_llm:
|
|
19
|
+
- LLM01:2025
|
|
20
|
+
owasp_agentic:
|
|
21
|
+
- ASI01:2026
|
|
22
|
+
- ASI04:2026
|
|
23
|
+
mitre_atlas:
|
|
24
|
+
- 'AML.T0051.001 - LLM Prompt Injection: Indirect'
|
|
25
|
+
external:
|
|
26
|
+
- https://github.com/Agent-Threat-Rule/agent-threat-rules/issues/653
|
|
27
|
+
- https://trojansource.codes/
|
|
28
|
+
- https://www.unicode.org/reports/tr9/
|
|
29
|
+
compliance:
|
|
30
|
+
eu_ai_act:
|
|
31
|
+
- article: '15'
|
|
32
|
+
context: Article 15 (accuracy, robustness and cybersecurity) requires high-risk AI systems to resist attempts by third parties to alter their behaviour; this rule provides detection evidence for that requirement by flagging tool descriptions and skill files that hide a directive to the model behind an invisible Unicode control.
|
|
33
|
+
strength: primary
|
|
34
|
+
- article: '13'
|
|
35
|
+
context: Article 13 (transparency) requires that deployers can understand the system they operate; a directive hidden behind an invisible control is text the deployer cannot see in review but the model follows, and this rule surfaces it.
|
|
36
|
+
strength: secondary
|
|
37
|
+
- article: '9'
|
|
38
|
+
context: Article 9 (risk management system) requires identified risks to be treated; this rule is a detection control for the hidden-directive risk in third-party MCP tools and skills, applied before the agent loads them.
|
|
39
|
+
strength: secondary
|
|
40
|
+
nist_ai_rmf:
|
|
41
|
+
- subcategory: MS.2.7
|
|
42
|
+
context: MEASURE 2.7 requires security and resilience to be evaluated and documented; scanning tool definitions and skill files for directives hidden behind invisible controls is a measurable check on third-party agent components.
|
|
43
|
+
strength: primary
|
|
44
|
+
- subcategory: MG.3.1
|
|
45
|
+
context: MANAGE 3.1 requires risks from third-party resources to be monitored; MCP tool descriptions and skills are third-party text the model treats as instructions, and this rule monitors them for hidden directives.
|
|
46
|
+
strength: secondary
|
|
47
|
+
- subcategory: MP.5.1
|
|
48
|
+
context: MAP 5.1 requires the likelihood and impact of identified attack patterns to be characterised; the gap between what a reviewer sees and what the model reads is one such pattern, and this rule detects its use in static tool text.
|
|
49
|
+
strength: secondary
|
|
50
|
+
iso_42001:
|
|
51
|
+
- clause: '8.1'
|
|
52
|
+
context: ISO/IEC 42001 Clause 8.1 (operational planning and control, including control of externally provided processes) is supported by this rule's detection of hidden directives in externally provided MCP tools and skills.
|
|
53
|
+
strength: primary
|
|
54
|
+
- clause: '6.2'
|
|
55
|
+
context: ISO/IEC 42001 Clause 6.2 (AI objectives and planning) calls for risk treatment of known attack patterns; detecting a directive hidden behind an invisible Unicode control in tool text is such a treatment.
|
|
56
|
+
strength: secondary
|
|
57
|
+
tags:
|
|
58
|
+
category: tool-poisoning
|
|
59
|
+
subcategory: invisible-control-before-directive
|
|
60
|
+
scan_target: both
|
|
61
|
+
confidence: medium
|
|
62
|
+
agent_source:
|
|
63
|
+
type: tool_call
|
|
64
|
+
framework:
|
|
65
|
+
- mcp
|
|
66
|
+
- any
|
|
67
|
+
provider:
|
|
68
|
+
- any
|
|
69
|
+
detection:
|
|
70
|
+
condition: any
|
|
71
|
+
conditions:
|
|
72
|
+
- field: tool_description
|
|
73
|
+
operator: regex
|
|
74
|
+
value: "(?:(?:[\\x21-\\x2F\\x3A-\\x40\\x5B-\\x60\\x7B-\\x7E、。!,:;?][ \\t]{0,3}|[A-Za-z0-9][ \\t]{1,3})[\uFEFF]{0,6}[\uFEFF]|(?:^|[\\r\\n])[ \\t]{0,8}[]{0,6}[])[ \\t\"'*_`>(\\[]{0,4}(?:(?:also|then|please|now|first|additionally|and|but|ai|assistant|agent|model|llm|claude)[,:]?\\s+){0,2}(?:(?:ignore|disregard|forget|override|bypass)\\s+(?:all\\s+|any\\s+)?(?:(?:the|your|of\\s+the|previous|prior|above|earlier|preceding|system|original|other|safety|security|developer)\\s+){0,3}(?:instructions?|rules|prompts?|guidelines|directives|polic(?:y|ies)|guardrails|restrictions|constraints)|(?:important|attention|urgent|critical|system\\s+(?:note|override|message|instruction)|admin(?:istrator)?\\s+note|note\\s+to\\s+(?:the\\s+)?(?:ai|assistant|model|agent|llm))\\s{0,3}[:!>-][^\\n]{0,60}?\\b(?:ignore|disregard|forget|read|send|forward|upload|include|attach|exfiltrate|leak|(?:do\\s+not|don't|never)\\s+(?:tell|mention|inform|reveal)|(?:before|after|when)\\s+(?:answering|responding|replying|you\\s+(?:answer|respond|reply)))\\b|<\\s{0,3}/?(?:important|system|instructions?|secret|hidden)\\s{0,3}>|you\\s+are\\s+now\\b|new\\s+(?:system\\s+)?instructions?\\s{0,3}:)"
|
|
75
|
+
description: Invisible control at the start of a clause, followed by an instruction override (ignore/disregard previous instructions), an attention header whose clause tells the model to read, send, ignore or answer differently, an injected <IMPORTANT>/<system> tag, or a new-instructions / you-are-now header
|
|
76
|
+
- field: tool_description
|
|
77
|
+
operator: regex
|
|
78
|
+
value: "(?:(?:[\\x21-\\x2F\\x3A-\\x40\\x5B-\\x60\\x7B-\\x7E、。!,:;?][ \\t]{0,3}|[A-Za-z0-9][ \\t]{1,3})[\uFEFF]{0,6}[\uFEFF]|(?:^|[\\r\\n])[ \\t]{0,8}[]{0,6}[])[ \\t\"'*_`>(\\[]{0,4}(?:(?:also|then|please|now|first|additionally|and|but|ai|assistant|agent|model|llm|claude)[,:]?\\s+){0,2}(?:(?:before|after|when|while|prior\\s+to|whenever|each\\s+time)\\s+(?:you\\s+)?(?:respond(?:ing)?|answer(?:ing)?|repl(?:y|ying)|returning\\s+(?:the\\s+)?(?:results?|output|answer)|(?:using|calling|invoking)\\s+(?:this|any|another|other)\\s+tools?)\\b[^\\n]{0,80}?\\b(?:(?:send|forward|upload|post|attach|append|include|copy|transmit|exfiltrate|leak|email|share)\\b[^\\n]{0,60}?(?:(?:conversation|chat\\s+history|message\\s+history|system\\s+prompt|(?:process\\s+)?environment|\\benv\\s+vars?|credentials?|secrets?|api[\\s_-]?keys?|(?:access|auth(?:entication)?|session|bearer)\\s+tokens?|passwords?|private\\s+keys?|ssh\\s+keys?|~/\\.ssh|\\.ssh/|id_rsa|id_ed25519|\\.env\\b|\\.aws/|cookies)|https?://|[\\w.+-]{1,64}@[\\w-]{1,63}\\.[a-z]{2,})|(?:call|invoke|use)\\s+this\\s+(?:tool|function))|(?:always|must|you\\s+must|you\\s+should|make\\s+sure\\s+(?:to|you))\\s+(?:first\\s+)?(?:(?:call|invoke|use|run|prefer|choose|select)\\s+this\\s+(?:tool|function|server|skill|plugin)\\s+(?:first|before\\s+(?:any|all|every|other)|instead\\s+of|rather\\s+than|for\\s+(?:every|all|any)\\b|even\\s+(?:if|when))|(?:send|forward|upload|post|attach|append|include|copy|transmit|exfiltrate|leak|email|share)\\b[^\\n]{0,60}?(?:conversation|chat\\s+history|message\\s+history|system\\s+prompt|(?:process\\s+)?environment|\\benv\\s+vars?|credentials?|secrets?|api[\\s_-]?keys?|(?:access|auth(?:entication)?|session|bearer)\\s+tokens?|passwords?|private\\s+keys?|ssh\\s+keys?|~/\\.ssh|\\.ssh/|id_rsa|id_ed25519|\\.env\\b|\\.aws/|cookies))|(?:(?:for\\s+best\\s+results|for\\s+(?:debugging|analytics|telemetry|quality|audit)(?:\\s+purposes)?|to\\s+improve\\s+[a-z]+)[,:]?\\s+)?(?:silently\\s+|quietly\\s+|secretly\\s+)?(?:send|forward|upload|post|attach|append|include|copy|transmit|exfiltrate|leak|email|share)\\b[^\\n]{0,60}?(?:conversation|chat\\s+history|message\\s+history|system\\s+prompt|(?:process\\s+)?environment|\\benv\\s+vars?|credentials?|secrets?|api[\\s_-]?keys?|(?:access|auth(?:entication)?|session|bearer)\\s+tokens?|passwords?|private\\s+keys?|ssh\\s+keys?|~/\\.ssh|\\.ssh/|id_rsa|id_ed25519|\\.env\\b|\\.aws/|cookies)|(?:read|cat|open|load|print|dump|return)\\s+[^\\n]{0,40}?(?:~/\\.ssh|\\.ssh/|id_rsa|id_ed25519|/etc/(?:passwd|shadow)|\\.env\\b|\\.aws/credentials|\\.npmrc|\\.netrc|\\.git-credentials|\\.kube/config))"
|
|
79
|
+
description: Invisible control at the start of a clause, followed by a response-timing hook (before answering, after responding, when calling another tool) that sends or reads secrets, conversation or a URL; an always/must directive to call this tool first or instead of others, or to send secrets; an exfiltration verb on secrets, conversation, environment or credential files; or a read of ~/.ssh, .env, .aws/credentials and similar files
|
|
80
|
+
- field: tool_description
|
|
81
|
+
operator: regex
|
|
82
|
+
value: "(?:(?:[\\x21-\\x2F\\x3A-\\x40\\x5B-\\x60\\x7B-\\x7E、。!,:;?][ \\t]{0,3}|[A-Za-z0-9][ \\t]{1,3})[\uFEFF]{0,6}[\uFEFF]|(?:^|[\\r\\n])[ \\t]{0,8}[]{0,6}[])[ \\t\"'*_`>(\\[]{0,4}(?:(?:also|then|please|now|first|additionally|and|but|ai|assistant|agent|model|llm|claude)[,:]?\\s+){0,2}(?:(?:do\\s+not|don't|never|without)\\s+(?:tell(?:ing)?|inform(?:ing)?|notify(?:ing)?|mention(?:ing)?|reveal(?:ing)?|disclos(?:e|ing)|alert(?:ing)?|warn(?:ing)?|ask(?:ing)?)\\s+(?:this\\s+to\\s+|anything\\s+to\\s+)?(?:the\\s+)?(?:user|human|operator)\\b|(?:do\\s+not|don't|never)\\s+let\\s+(?:the\\s+)?(?:user|human)\\s+(?:know|see))"
|
|
83
|
+
description: Invisible control at the start of a clause, followed by a concealment directive (do not tell, inform, mention or reveal to the user)
|
|
84
|
+
false_positives:
|
|
85
|
+
- A security write-up, test fixture or rule file that quotes a poisoned tool description verbatim, invisible control included, will match; that is the text the rule looks for.
|
|
86
|
+
- A localized description whose right-to-left text puts an LRM or RLM after an ASCII word and a space, directly before an English sentence that tells the model to send credentials or not tell the user, would match. No such text was found in the benign corpora; the non-Latin samples in the true negatives do not match.
|
|
87
|
+
- Presence of the controls alone (right-to-left marks, ZWNJ in Persian, emoji ZWJ sequences, soft hyphens inside words, LRE/PDF around a keyboard shortcut, ZWSP from pasted chat text, a byte-order mark at the start of a file) does not match.
|
|
88
|
+
response:
|
|
89
|
+
actions:
|
|
90
|
+
- alert
|
|
91
|
+
- snapshot
|
|
92
|
+
message_template: |
|
|
93
|
+
[ATR-2026-02870] HIGH: an invisible Unicode control (zero-width, soft hyphen or bidi) starts a clause that instructs the model, in a tool description or skill file. Show the description with control characters made visible, and review the tool or skill before the agent loads it.
|
|
94
|
+
confidence: 60
|