Skip to content

Commit fcc16c1

Browse files
committed
spec: add agent-threat-scan predicate type
Adds a new predicate type for recording the result of scanning an AI agent artifact (MCP server, Claude Code skill, or similar) against a named detection ruleset. Ruleset-agnostic: references ruleset.uri and ruleset.version so any detection standard issuing stable rule IDs can be used. Registers spec/predicates/agent-threat-scan.md and adds it to the vetted predicates list in spec/predicates/README.md. Predicate URI: https://in-toto.io/attestation/agent-threat-scan/v0.1 Signed-off-by: Adam Lin <adam@agentthreatrule.org>
1 parent 51da3c9 commit fcc16c1

2 files changed

Lines changed: 207 additions & 0 deletions

File tree

spec/predicates/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ community! Please see our [New Predicate Guidelines].
1212
This directory contains predicate specification types that have gone through
1313
our [vetting process], and may be of general interest:
1414

15+
- [Agent Threat Scan]: Records the result of scanning an AI agent artifact
16+
against a named detection ruleset.
1517
- [CycloneDX]: CycloneDX BOM for software artifacts.
1618
<!-- markdownlint-disable-next-line MD059 -->
1719
- [Link]: For migration from [in-toto 0.9].
@@ -32,6 +34,7 @@ our [vetting process], and may be of general interest:
3234
- [VULNS]: Defines the metadata to share the results of vulnerability scanning
3335
on software artifacts.
3436

37+
[Agent Threat Scan]: agent-threat-scan.md
3538
[CycloneDX]: https://cyclonedx.org/
3639
[Link]: link.md
3740
[New Predicate Guidelines]: ../../docs/new_predicate_guidelines.md
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
# Predicate type: Agent Threat Scan
2+
3+
Type URI: https://in-toto.io/attestation/agent-threat-scan/v0.1
4+
5+
Version: 0.1
6+
7+
Authors: Adam Lin (@eeee2345)
8+
9+
## Purpose
10+
11+
The Agent Threat Scan predicate communicates that an AI agent artifact (such as
12+
a Model Context Protocol server, a Claude Code skill, or another agent
13+
configuration manifest) has been scanned against a named detection ruleset for
14+
agent-specific threats including prompt injection, tool poisoning, MCP request
15+
forgery, and skill compromise. It enables consumers of agent artifacts to
16+
verify which ruleset and ruleset version were applied, what the scan outcome
17+
was, and which rules (if any) matched, without needing to re-run the scan or
18+
read the full set of rule definitions.
19+
20+
## Use Cases
21+
22+
Existing predicates such as Vulnerabilities (vulns), Test Result, and Simple
23+
Verification Result do not capture the structure of agent-specific scanning.
24+
Vulnerability scanners are oriented around package CVEs in conventional
25+
software artifacts. Test Result is generic and does not carry the
26+
ruleset-versioning, rule-identifier, and threat-class taxonomy that are
27+
characteristic of agent threat detection. Simple Verification Result records
28+
that policies passed but does not enumerate which rules matched on a fail.
29+
30+
Concrete use cases the Agent Threat Scan predicate enables include the
31+
following. A registry of MCP servers can require an attestation that an
32+
artifact was scanned with a named open ruleset at or above a minimum version
33+
before the artifact is listed. A CI pipeline producing agent skills can attach
34+
the predicate to released artifacts so downstream consumers can decide whether
35+
to install. A policy engine can answer the question, was this agent scanned
36+
with ruleset X version Y on date Z, and did any rules of severity high or
37+
critical match.
38+
39+
## Prerequisites
40+
41+
This predicate depends on the in-toto Attestation Framework and on the
42+
existence of a named detection ruleset that issues stable rule identifiers.
43+
One example of such a ruleset is Agent Threat Rules (ATR), an open detection
44+
standard for AI agent threats licensed Apache-2.0, available at
45+
https://github.com/Agent-Threat-Rule/agent-threat-rules. The predicate is not
46+
tied to ATR; any ruleset that issues stable identifiers and a version may be
47+
referenced through the ruleset.uri and ruleset.version fields. ATR is shipped
48+
in production at Cisco AI Defense and Microsoft agent-governance-toolkit.
49+
50+
## Model
51+
52+
An Agent Threat Scan attestation declares that a named scanner, applying a
53+
named ruleset at a specific version, evaluated the subject artifact at
54+
scannedAt and produced an outcome of pass, warn, or fail, optionally
55+
enumerating the rules that matched. Multiple Agent Threat Scan attestations
56+
can be produced for the same subject across rulesets or across time. The
57+
predicate does not include the rule definitions themselves; it references
58+
them by stable identifier and by ruleset version so that consumers can resolve
59+
them through the ruleset.uri.
60+
61+
## Schema
62+
63+
```jsonc
64+
{
65+
// Standard attestation fields:
66+
"_type": "https://in-toto.io/Statement/v1",
67+
"subject": [{ ... }],
68+
69+
// Predicate:
70+
"predicateType": "https://in-toto.io/attestation/agent-threat-scan/v0.1",
71+
"predicate": {
72+
"scanner": {
73+
"uri": "<URI>",
74+
"version": "<STRING>"
75+
},
76+
"ruleset": {
77+
"uri": "<URI>",
78+
"version": "<STRING>"
79+
},
80+
"scannedAt": "<TIMESTAMP>",
81+
"outcome": "pass|warn|fail",
82+
"matches": [
83+
{
84+
"ruleId": "<STRING>",
85+
"severity": "low|medium|high|critical",
86+
"threatClass": "<STRING>",
87+
"evidence": "<STRING>"
88+
}
89+
]
90+
}
91+
}
92+
```
93+
94+
### Parsing Rules
95+
96+
This predicate follows the
97+
[in-toto Attestation Framework's parsing rules](../v1/README.md#parsing-rules).
98+
99+
### Fields
100+
101+
**`scanner`, required** object
102+
103+
> Identifies the tool that performed the scan.
104+
105+
**`scanner.uri`, required** string (ResourceURI)
106+
107+
> URI identifying the scanner. May reference a package, repository, or service.
108+
109+
**`scanner.version`, optional** string
110+
111+
> The version of the scanner.
112+
113+
**`ruleset`, required** object
114+
115+
> Identifies the detection ruleset applied during the scan.
116+
117+
**`ruleset.uri`, required** string (ResourceURI)
118+
119+
> URI identifying the ruleset. SHOULD resolve to a definition of the rules,
120+
> or to documentation describing how to resolve a rule identifier to its
121+
> rule definition.
122+
123+
**`ruleset.version`, required** string
124+
125+
> The version of the ruleset that was applied. The version SHOULD be stable
126+
> and citable so that a consumer can re-resolve any ruleId in matches against
127+
> the exact ruleset version used.
128+
129+
**`scannedAt`, required** string (Timestamp)
130+
131+
> RFC 3339 timestamp indicating when the scan completed.
132+
133+
**`outcome`, required** string
134+
135+
> One of pass, warn, or fail. pass means no rules matched. warn means at most
136+
> rules below the producer's chosen blocking threshold matched. fail means at
137+
> least one rule at or above the blocking threshold matched. Producers SHOULD
138+
> document their threshold mapping where the predicate is consumed.
139+
140+
**`matches`, optional** array of object
141+
142+
> The list of rules that matched on the subject. MAY be empty when outcome
143+
> is pass. SHOULD be present and non-empty when outcome is warn or fail.
144+
145+
**`matches[*].ruleId`, required** string
146+
147+
> The stable identifier of the rule that matched, as issued by the ruleset.
148+
149+
**`matches[*].severity`, optional** string
150+
151+
> One of low, medium, high, critical. The severity assigned by the ruleset
152+
> to the matched rule.
153+
154+
**`matches[*].threatClass`, optional** string
155+
156+
> A short label describing the class of threat the rule covers, such as
157+
> prompt_injection, tool_poisoning, mcp_request_forgery, or skill_compromise.
158+
159+
**`matches[*].evidence`, optional** string
160+
161+
> A free-form string containing scanner-specific evidence such as a snippet,
162+
> a path within the subject, or a hash. Producers SHOULD avoid including
163+
> sensitive content in this field.
164+
165+
## Example
166+
167+
```jsonc
168+
{
169+
"_type": "https://in-toto.io/Statement/v1",
170+
"subject": [
171+
{
172+
"name": "example-mcp-server-1.2.3.tgz",
173+
"digest": {"sha256": "fe4fe40ac7250263c5dbe1cf3138912f3f416140aa248637a60d65fe22c47da4"}
174+
}
175+
],
176+
"predicateType": "https://in-toto.io/attestation/agent-threat-scan/v0.1",
177+
"predicate": {
178+
"scanner": {
179+
"uri": "pkg:npm/%40panguard-ai/cli@1.4.13",
180+
"version": "1.4.13"
181+
},
182+
"ruleset": {
183+
"uri": "https://github.com/Agent-Threat-Rule/agent-threat-rules",
184+
"version": "v2.0.17"
185+
},
186+
"scannedAt": "2026-05-09T10:00:00Z",
187+
"outcome": "fail",
188+
"matches": [
189+
{
190+
"ruleId": "ATR-2026-00081",
191+
"severity": "high",
192+
"threatClass": "prompt_injection",
193+
"evidence": "tools[2].description contained a hidden instruction directive"
194+
}
195+
]
196+
}
197+
}
198+
```
199+
200+
## Changelog and Migrations
201+
202+
Not applicable for this initial version.
203+
204+
[Attestation]: ../README.md

0 commit comments

Comments
 (0)