diff --git a/.claude/skills/add-ave-record/SKILL.md b/.claude/skills/add-ave-record/SKILL.md index e9b0998..3d4d24f 100644 --- a/.claude/skills/add-ave-record/SKILL.md +++ b/.claude/skills/add-ave-record/SKILL.md @@ -120,6 +120,8 @@ A record passing validation is not yet a published one. Update: - **dist/ave-records-latest.json**: add or replace this record's entry, keeping the array sorted by ave_id. +- **dist/ave-taxonomy-latest.json**: regenerate it from that file with + `python3 scripts/build_taxonomy.py` (`--check` confirms they agree). - **CHANGELOG.md**: one line under Unreleased/Added: the ave_id, title, severity, and aivss_score. - **README.md, three separate things, don't assume any of them share a diff --git a/.github/workflows/regenerate-records-json.yml b/.github/workflows/regenerate-records-json.yml index d611ce4..6b7b965 100644 --- a/.github/workflows/regenerate-records-json.yml +++ b/.github/workflows/regenerate-records-json.yml @@ -1,6 +1,7 @@ name: Regenerate consolidated records JSON -# Keeps dist/ave-records-latest.json current automatically, and creates +# Keeps dist/ave-records-latest.json and dist/ave-taxonomy-latest.json current +# automatically, and creates # dist/ave-records-v.json the first time a schema version appears # (never rewritten after that -- see scripts/build-records.js). # Triggers on every push to develop that touches records/ -- the repo that @@ -37,6 +38,9 @@ jobs: - name: Regenerate consolidated records JSON run: node scripts/build-records.js + - name: Regenerate the AVE SARIF taxonomy + run: python3 scripts/build_taxonomy.py + - name: Open PR if dist/ changed uses: peter-evans/create-pull-request@v8 with: @@ -50,9 +54,11 @@ jobs: commit-message: "chore: regenerate consolidated records JSON" title: "chore: regenerate consolidated records JSON" body: | - Auto-generated by `scripts/build-records.js` after a change to - `records/` on `develop`. Regenerates `dist/ave-records-latest.json` - (and its manifest) to stay in sync with the current record set. + Auto-generated by `scripts/build-records.js` and + `scripts/build_taxonomy.py` after a change to `records/` on + `develop`. Regenerates `dist/ave-records-latest.json` (and its + manifest) and `dist/ave-taxonomy-latest.json` to stay in sync with + the current record set. The versioned `dist/ave-records-v.json` snapshot is only touched the first time a given schema version appears -- if this diff includes one, that means a new schema version's diff --git a/CHANGELOG.md b/CHANGELOG.md index 40cb79a..ecb9fd0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,20 @@ Format: [Semantic Versioning](https://semver.org). Schema versions and record se ## [Unreleased] +### SARIF +- **The AVE taxonomy as a canonical file, form C and taxonomy checks** (#420). `dist/ave-taxonomy-latest.json` is the AVE + taxonomy as a SARIF 2.1.0 `toolComponent` with a frozen `guid` (`5110b285-34d7-5334-94db-0308b24cfb49`, the UUIDv5 of + `https://aveproject.org/taxonomy/AVE`) and one taxon per record, including records whose status is not `active`. + `scripts/build_taxonomy.py` builds it deterministically from `dist/ave-records-latest.json` (`--check` fails when it is + stale; `--only` builds the subset a scanner embeds; `--release`, `--release-date` and `--download-uri` stamp a release), + and the workflow that regenerates `dist/` rebuilds it. `docs/specs/ave-in-sarif.md` moves to v1.2: form C (a tool's own + `ruleId`, a rule `relationships` link to the AVE taxonomy, `result.taxa` and `supportedTaxonomies`, recommending `kinds` + `["relevant"]` and saying why), the guid as the taxonomy's identity, and a form C example. `scripts/ave_conformance.py` + reads form C and gains six checks: `taxonomy_guid_missing`, `taxonomy_guid_mismatch`, `taxon_unknown`, + `taxon_name_differs`, `reference_guid_mismatch` and `supported_taxonomies_missing`. Forms A and B are unchanged. The + generated file mirrors record text exactly, so it carries the em dashes that AVE-2026-00050 and 00051 have in their + titles and description until those records are corrected. + ### Records - **Eight cut-off fingerprints repaired** (#414). AVE-2026-00023, 00026, 00029, 00030, 00033, 00038, 00039 and 00040 had a `behavioral_fingerprint` that stopped mid-word at exactly 200 characters (`... human oversight diff --git a/CLAUDE.md b/CLAUDE.md index 74c9274..78c4b1a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -146,6 +146,7 @@ def validate_record(record: dict) -> tuple[bool, list[str]]: ```bash npm install ajv ajv-formats # schema validation deps node scripts/build-records.js # build dist/ave-records-latest.json +python3 scripts/build_taxonomy.py # build dist/ave-taxonomy-latest.json from it (--check: fail if stale) # Python validation pip install -e ".[dev]" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 06613e3..9080a17 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -169,6 +169,7 @@ python scripts/check_mutation_thm_trail.py --strict --only AVE-2026-NNNNN # if python scripts/check_framework_sources.py --strict --only AVE-2026-NNNNN # CI enforces this for every record now; run it scoped to yours before pushing, same check either way python scripts/generate_terms.py # regenerate docs/terms.md after any schema field or description change python scripts/check_terms_sync.py # hard failure if docs/terms.md disagrees with the live schema -- run before opening a PR +python3 scripts/build_taxonomy.py --check # dist/ave-taxonomy-latest.json must match dist/ave-records-latest.json; run python3 scripts/build_taxonomy.py after you change that file pytest tests/ -x -q # full suite: schema, AIVSS arithmetic, mitigation enums ``` diff --git a/dist/ave-records-latest.json b/dist/ave-records-latest.json index 07a3f94..612bd83 100644 --- a/dist/ave-records-latest.json +++ b/dist/ave-records-latest.json @@ -51,6 +51,13 @@ "private_data" ] }, + "security_boundary": "component's own declared tool scope → the shared tool-dispatch layer every component's calls route through, which one component can silently claim authority over", + "missing_control": "no isolation or authorization check preventing one component's hook registration from intercepting calls belonging to other components", + "vulnerability_rationale": { + "capability": "Components can register hooks/callbacks into the agent's tool dispatch layer.", + "vulnerability": "No authorization or integrity check on hook registration into a shared dispatch layer that all components' tool calls pass through.", + "impact": "A hook registered early silently intercepts or redirects all subsequent tool invocations, including those of other skills and system tools, to attacker-controlled callbacks, while the agent continues to believe it is calling the legitimate tool." + }, "mitigation": { "strategy": [ "deny_by_default", @@ -81,7 +88,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-05-16T00:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "CWE-601", @@ -227,6 +234,13 @@ "private_data" ] }, + "security_boundary": "reviewed artifact → executed artifact, with a mutable external fetch sitting unchecked between the two", + "missing_control": "no pinning or integrity check on runtime-fetched content that replaces a component's own behavior", + "vulnerability_rationale": { + "capability": "A skill or MCP component can fetch and execute remote content at runtime.", + "vulnerability": "No integrity binding exists between what was reviewed (the artifact and its declared behavior at scan time) and what actually executes (mutable, externally-fetched content at run time).", + "impact": "The fetched content replaces the component's original instructions, so an attacker can change its behavior after it has passed security review." + }, "mitigation": { "strategy": [ "pin_integrity", @@ -271,7 +285,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-01T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Greshake 2023", @@ -376,6 +390,13 @@ "untrusted_content" ] }, + "security_boundary": "tool metadata (should be descriptive, inert) → agent instruction (treated as authoritative context)", + "missing_control": "no structural separation between descriptive metadata and executable instruction within the tool manifest schema", + "vulnerability_rationale": { + "capability": "MCP tool description fields are read by the agent during tool discovery.", + "vulnerability": "No boundary separates \"metadata describing a tool\" from \"instructions the agent should follow\"; both share the same natural-language channel with nothing to distinguish them.", + "impact": "The agent treats the embedded instructions as authoritative context and follows attacker-controlled directives, before any tool is called." + }, "mitigation": { "strategy": [ "validate_input", @@ -420,7 +441,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-01T09:00:00Z", - "last_updated": "2026-08-29T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Greshake 2023", @@ -522,6 +543,13 @@ "external_comms" ] }, + "security_boundary": "tool-use decision → irreversible on-chain action", + "missing_control": "no structurally mandatory (vs. component-configurable) approval gate for irreversible financial actions specifically", + "vulnerability_rationale": { + "capability": "Agent with wallet tool access can transfer funds/approve allowances.", + "vulnerability": "No structurally mandatory human-approval gate exists for irreversible financial actions specifically.", + "impact": "Irreversible on-chain financial loss." + }, "mitigation": { "strategy": [ "require_human_approval", @@ -544,7 +572,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "MITRE ATT&CK T1657", @@ -674,6 +702,13 @@ "private_data" ] }, + "security_boundary": "discovery-layer metadata (read once, pre-execution) → agent context (treated as authoritative), with no execution-layer event for runtime monitoring to catch", + "missing_control": "no validation at server-card fetch time, and no detection surface at all for runtime/execution-layer monitoring, since nothing has executed yet", + "vulnerability_rationale": { + "capability": "An agent fetches and reads a server-card's tool descriptions before making any tool call.", + "vulnerability": "No boundary separates metadata describing a tool from instructions the agent should follow, here at the discovery layer: the server card is read before any tool call exists for runtime monitoring to observe.", + "impact": "Malicious instructions in tool descriptions, parameter descriptions or config schemas are loaded into the agent's context and executed immediately, before any user interaction and outside runtime monitoring's reach." + }, "mitigation": { "strategy": [ "validate_input", @@ -703,7 +738,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-05-01T00:00:00Z", - "last_updated": "2026-08-29T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Greshake 2023", @@ -831,6 +866,13 @@ "untrusted_content" ] }, + "security_boundary": "task-result data (should be data) → trusted context from a \"completed\" task", + "missing_control": "no validation distinguishes result data from instruction, and the dispatch-to-consumption temporal gap bypasses synchronous safety checks", + "vulnerability_rationale": { + "capability": "Agent dispatches async tasks and later reads their results in a future turn.", + "vulnerability": "No validation distinguishes legitimate result data from instruction, and the temporal gap bypasses checks applied at dispatch time.", + "impact": "Injected content is treated as trusted context from a completed task rather than external, untrusted input." + }, "mitigation": { "strategy": [ "validate_input", @@ -861,7 +903,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-05-01T00:00:00Z", - "last_updated": "2026-09-27T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Greshake 2023", @@ -1156,6 +1198,13 @@ "untrusted_content" ] }, + "security_boundary": "parent's full permission set → sub-agent, by default", + "missing_control": "no explicit trust-boundary or permission-scoping requirement on delegation", + "vulnerability_rationale": { + "capability": "Agent can delegate tasks to sub-agents or spawn child agents.", + "vulnerability": "No explicit trust boundary or permission-scoping requirement exists on delegation; sub-agents inherit full parent permissions by default.", + "impact": "Privilege laundering and audit evasion, since sub-agent actions may not appear in the parent's audit trail." + }, "mitigation": { "strategy": [ "least_privilege", @@ -1186,7 +1235,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-05-16T00:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "CWE-269", @@ -1436,7 +1485,7 @@ "schema_version": "1.3.0", "status": "active", "published": "2026-06-21T00:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "component_type": "mcp_server", "title": "Parasitic Toolchain — Silent Tool Registration and Persistent Hook Injection", "attack_class": "Persistence - Parasitic Toolchain", @@ -1488,6 +1537,13 @@ "external_comms" ] }, + "security_boundary": "declared manifest scope → actual runtime tool-registry footprint", + "missing_control": "no conformance check between a component's registered footprint and its declared manifest", + "vulnerability_rationale": { + "capability": "Tools can register handlers into the agent's tool dispatch layer at runtime.", + "vulnerability": "No check verifies a component's actual registered footprint against its declared manifest, at registration or session restart.", + "impact": "A persistent, undeclared capability survives context resets, indistinguishable from a legitimately registered tool." + }, "mitigation": { "strategy": [ "deny_by_default", @@ -1602,7 +1658,7 @@ "schema_version": "1.3.0", "status": "active", "published": "2026-06-21T00:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "component_type": "mcp_server", "title": "OAuth Discovery Rebinding — Authorization Endpoint Redirected to Attacker Server", "attack_class": "Supply Chain - OAuth Discovery Rebinding", @@ -1650,6 +1706,13 @@ "external_comms" ] }, + "security_boundary": "server's declared origin → discovery-document endpoint values (unverified)", + "missing_control": "no verification that discovery-document endpoints match the server's own declared origin", + "vulnerability_rationale": { + "capability": "Agent follows OAuth 2.0 Authorization Server Metadata / OIDC Discovery per the published standard.", + "vulnerability": "No verification that discovery-document endpoint values match the server's own declared origin before the agent trusts them.", + "impact": "Interception of authorization codes, access tokens, and credentials during the OAuth exchange." + }, "mitigation": { "strategy": [ "verify_identity", @@ -1953,6 +2016,13 @@ "private_data" ] }, + "security_boundary": "configuration data → process-spawn boundary", + "missing_control": "no validation gate between configuration/registry data and process execution", + "vulnerability_rationale": { + "capability": "An MCP client spawns a server as a subprocess using command/args from configuration data.", + "vulnerability": "No validation gate exists between untrusted configuration data and the process-spawn boundary.", + "impact": "Arbitrary OS command execution under the client's privileges before any protocol handshake occurs." + }, "mitigation": { "strategy": [ "deny_by_default", @@ -1978,7 +2048,7 @@ "researcher": "OX Security", "researcher_url": "https://www.ox.security", "published": "2026-07-10T00:00:00Z", - "last_updated": "2026-07-10T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "OX Security", @@ -2118,6 +2188,13 @@ "private_data" ] }, + "security_boundary": "per-description review (isolated) → multi-description composition (never reviewed as a whole)", + "missing_control": "no cross-description, holistic review step exists", + "vulnerability_rationale": { + "capability": "MCP tool descriptions across multiple tools/servers are individually reviewed for malicious content.", + "vulnerability": "No cross-description review step exists; review is structurally confined to one description at a time.", + "impact": "A complete malicious instruction assembles at inference time with no single reviewable artifact ever having existed." + }, "mitigation": { "strategy": [ "validate_input", @@ -2145,7 +2222,7 @@ "researcher": "Liu et al.", "researcher_url": "https://arxiv.org/abs/2606.27027", "published": "2026-07-15T00:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "ShareLock research", @@ -2385,6 +2462,13 @@ "private_data" ] }, + "security_boundary": "descriptive capability/identity metadata → instruction, once loaded into reasoning context", + "missing_control": "no boundary separates the A2A card's descriptive metadata from executable instruction once it is loaded into the host's reasoning context", + "vulnerability_rationale": { + "capability": "A host agent reads a remote agent's A2A card to plan task delegation.", + "vulnerability": "No boundary separates the card's descriptive metadata from executable instruction once loaded into the host's reasoning context.", + "impact": "Delegation planning hijacked by a malicious remote agent's self-declared, unverified metadata." + }, "mitigation": { "strategy": [ "validate_input", @@ -2409,7 +2493,7 @@ "researcher": "Kumar Aditya", "researcher_url": "https://www.keysight.com/blogs/en/tech/nwvs/2026/03/12/agent-card-poisoning", "published": "2026-07-27T00:00:00Z", - "last_updated": "2026-08-29T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Keysight research", @@ -2519,6 +2603,13 @@ "external_comms" ] }, + "security_boundary": "trust established at authoring/review time → trust required at every subsequent execution, with no mechanism re-checking the gap between them", + "missing_control": "no ongoing verification that an already-approved external anchor is still controlled by its original owner", + "vulnerability_rationale": { + "capability": "Skills reference external identities (GitHub owners, package names, domains) that were valid at authoring time.", + "vulnerability": "No periodic re-verification that a previously-valid external identity reference remains currently owned by the same party; trust is established once, at review time, and never rechecked against real-world ownership changes.", + "impact": "An attacker who registers the now-unclaimed name takes control of everything the skill points at, without a single byte of the skill's own committed content changing." + }, "mitigation": { "strategy": [ "verify_identity", @@ -2547,7 +2638,7 @@ "researcher": "AIR Security", "researcher_url": "https://www.air.security", "published": "2026-08-07T00:00:00Z", - "last_updated": "2026-10-13T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "repo-forensics dead-anchor scanner", @@ -3192,6 +3283,13 @@ "external_comms" ] }, + "security_boundary": "credential store → external destination", + "missing_control": "no content-aware egress control distinguishes legitimate outbound task data from credential exfiltration", + "vulnerability_rationale": { + "capability": "Agent can read env vars/credentials and make external network calls.", + "vulnerability": "No content-aware egress control distinguishes legitimate outbound task data from credential exfiltration.", + "impact": "Credential theft enabling follow-on compromise." + }, "mitigation": { "strategy": [ "least_privilege", @@ -3236,7 +3334,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-01T09:00:00Z", - "last_updated": "2026-08-23T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "CWE-522", @@ -3639,6 +3737,13 @@ "untrusted_content" ] }, + "security_boundary": "trusted system instruction ↔ untrusted component content, same channel", + "missing_control": "no instruction-hierarchy enforcement distinguishes origin or recency", + "vulnerability_rationale": { + "capability": "Agent processes instruction-shaped text from untrusted components in the same channel as trusted system instructions.", + "vulnerability": "No instruction-hierarchy enforcement distinguishes trusted origin from untrusted, recently-seen text.", + "impact": "Complete behavioral takeover, enabling most other AVE attack classes as a follow-on payload." + }, "mitigation": { "strategy": [ "validate_input", @@ -3661,7 +3766,7 @@ "researcher": "Perez & Ribeiro", "researcher_url": "https://arxiv.org/abs/2211.09527", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Perez 2022", @@ -3788,6 +3893,13 @@ "untrusted_content" ] }, + "security_boundary": "task-scoped tool access → durable, cross-session system modification", + "missing_control": "no restriction prevents task-scoped filesystem/shell access from writing to persistence locations (cron, startup scripts)", + "vulnerability_rationale": { + "capability": "Agent has legitimate filesystem/shell tool access for its task.", + "vulnerability": "No restriction prevents that task-scoped access from writing to system-persistence locations.", + "impact": "Durable compromise surviving reboot, reinstallation, or removal attempts." + }, "mitigation": { "strategy": [ "least_privilege", @@ -3810,7 +3922,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Cohen 2024", @@ -3937,6 +4049,13 @@ "untrusted_content" ] }, + "security_boundary": "agent's own configuration (trusted, set once) → content the agent processes (untrusted, arbitrary)", + "missing_control": "no enforced separation between \"instructions that configure the agent\" and \"content the agent merely reads\"", + "vulnerability_rationale": { + "capability": "Agent operates under safety/alignment constraints configured independently of the content it processes.", + "vulnerability": "No boundary prevents processed content from redefining the agent's own safety/alignment configuration; constraints that should be structurally immutable to in-context instruction are treated as negotiable.", + "impact": "The agent's built-in safety guidelines and ethical constraints are bypassed: it adopts an alternative identity that operates without restrictions." + }, "mitigation": { "strategy": [ "validate_input", @@ -3959,7 +4078,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-20T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Wei 2023", @@ -4084,6 +4203,13 @@ "untrusted_content" ] }, + "security_boundary": "component-issued instruction → operator/user visibility of that instruction", + "missing_control": "no enforced transparency requirement independent of what the component itself permits the agent to disclose", + "vulnerability_rationale": { + "capability": "Agent can withhold information from its own output.", + "vulnerability": "No requirement that instructions reaching the agent be disclosed to the user or operator on request; there's no operator-visibility boundary the component's instructions can't also suppress.", + "impact": "A covert channel between the component and the agent: the component directs the agent's behavior without the user's awareness or consent." + }, "mitigation": { "strategy": [ "validate_input", @@ -4106,7 +4232,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-20T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Greshake 2023", @@ -4227,6 +4353,13 @@ "untrusted_content" ] }, + "security_boundary": "task-descriptive content → direct tool-invocation command", + "missing_control": "no separation between content describing a task and content commanding a specific tool invocation with attacker-chosen parameters", + "vulnerability_rationale": { + "capability": "Agent selects and invokes tools based on task content.", + "vulnerability": "No boundary prevents component content from directly commanding tool invocations with attacker-chosen parameters, bypassing the agent's own selection logic.", + "impact": "Arbitrary tool invocation, including destructive, exfiltration, or lateral-movement capability the user never intended to activate." + }, "mitigation": { "strategy": [ "require_human_approval", @@ -4249,7 +4382,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-20T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Greshake 2023", @@ -4374,6 +4507,13 @@ "untrusted_content" ] }, + "security_boundary": "claimed permission (in-content) → actual authorization (never checked)", + "missing_control": "no verification checks an in-content permission claim against any real authorization system", + "vulnerability_rationale": { + "capability": "Agent can defer to permission claims made within its instruction context.", + "vulnerability": "No verification checks an in-content permission claim against any actual authorization system.", + "impact": "Agent performs actions it would otherwise refuse, believing itself newly authorized." + }, "mitigation": { "strategy": [ "verify_identity", @@ -4396,7 +4536,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-20T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "CWE-269", @@ -4522,6 +4662,13 @@ "external_comms" ] }, + "security_boundary": "PII in agent context → external destination", + "missing_control": "no content-aware egress control distinguishes legitimate task output from PII exfiltration", + "vulnerability_rationale": { + "capability": "Agent can access and transmit user PII in the course of normal tasks.", + "vulnerability": "No content-aware egress control distinguishes legitimate task output from PII exfiltration.", + "impact": "Identity theft, financial fraud, and regulatory-violation exposure for affected users." + }, "mitigation": { "strategy": [ "least_privilege", @@ -4544,7 +4691,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-20T09:00:00Z", - "last_updated": "2026-08-23T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "CWE-359", @@ -4667,6 +4814,13 @@ "untrusted_content" ] }, + "security_boundary": "internal configuration → normal output channel", + "missing_control": "no confidentiality boundary prevents the agent's own operational configuration from being repeated back through its ordinary output", + "vulnerability_rationale": { + "capability": "Agent's output channel can include any content it has processed, including its own system prompt.", + "vulnerability": "No confidentiality boundary prevents internal configuration from being repeated back through the normal output channel on request.", + "impact": "Proprietary logic and security-policy disclosure, revealing attack surface for follow-on exploitation." + }, "mitigation": { "strategy": [ "validate_input", @@ -4689,7 +4843,7 @@ "researcher": "Perez & Ribeiro", "researcher_url": "https://arxiv.org/abs/2211.09527", "published": "2026-04-20T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Perez 2022", @@ -4811,6 +4965,13 @@ "private_data" ] }, + "security_boundary": "retrieved document (should be data) → trusted context (treated as instruction)", + "missing_control": "no boundary distinguishes RAG-retrieved content from instruction", + "vulnerability_rationale": { + "capability": "A RAG pipeline retrieves external document content into agent context at query time.", + "vulnerability": "No boundary distinguishes retrieved document content from instruction once it enters context.", + "impact": "Attacker-controlled instructions execute via a corpus the attacker needs no direct system access to." + }, "mitigation": { "strategy": [ "sanitize_output", @@ -4854,7 +5015,7 @@ "researcher": "Zou et al.", "researcher_url": "https://arxiv.org/abs/2402.07867", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-29T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Greshake 2023", @@ -4953,6 +5114,13 @@ "untrusted_content" ] }, + "security_boundary": "claimed server identity → actual, verified identity (never checked)", + "missing_control": "no identity verification mechanism for MCP servers; trust follows a self-asserted manifest claim", + "vulnerability_rationale": { + "capability": "Agent grants trust and permission scope based on a server's claimed identity.", + "vulnerability": "No verification checks a claimed server identity against anything real.", + "impact": "A malicious server receives elevated trust and permissions it has no legitimate claim to." + }, "mitigation": { "strategy": [ "verify_identity", @@ -4996,7 +5164,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "CWE-290", @@ -5092,6 +5260,13 @@ "untrusted_content" ] }, + "security_boundary": "actual tool execution result → reported result (agent sits unchecked in the path)", + "missing_control": "no integrity check verifies a reported tool result matches what the tool actually returned", + "vulnerability_rationale": { + "capability": "Agent reports tool call results to users and downstream components.", + "vulnerability": "No integrity check verifies a reported result matches what the tool actually returned.", + "impact": "False information, hidden errors, or manipulated downstream decisions based on fabricated data." + }, "mitigation": { "strategy": [ "validate_input", @@ -5135,7 +5310,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Greshake 2023", @@ -5239,6 +5414,13 @@ "private_data" ] }, + "security_boundary": "write request (untrusted) → persistent memory store (should be trusted)", + "missing_control": "no provenance or integrity check gates writes to persistent memory", + "vulnerability_rationale": { + "capability": "Agent maintains persistent memory across sessions.", + "vulnerability": "No provenance or integrity check gates writes to the persistent memory store.", + "impact": "Attacker-controlled beliefs influence agent behavior across all future sessions, long after the initial write." + }, "mitigation": { "strategy": [ "validate_input", @@ -5282,7 +5464,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Cohen 2024", @@ -5383,6 +5565,13 @@ "untrusted_content" ] }, + "security_boundary": "orchestrator-intended output → sub-agent input, same channel", + "missing_control": "no boundary between task content and instruction at the agent-to-agent handoff specifically", + "vulnerability_rationale": { + "capability": "One agent's output becomes a downstream sub-agent's input in a delegation pipeline.", + "vulnerability": "No boundary distinguishes orchestrator-intended content from attacker-crafted instructions at the agent-to-agent handoff.", + "impact": "Downstream agent performs actions the orchestrator or user never intended, bypassing orchestrator-level safety controls." + }, "mitigation": { "strategy": [ "validate_input", @@ -5426,7 +5615,7 @@ "researcher": "Bawbel Security Research Team", "researcher_url": "https://bawbel.io", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-29T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Cohen 2024", @@ -5523,6 +5712,13 @@ "untrusted_content" ] }, + "security_boundary": "agent decision → irreversible/high-impact action", + "missing_control": "human confirmation is component-configurable behavior, not a structurally enforced gate", + "vulnerability_rationale": { + "capability": "Agent can take consequential or irreversible actions.", + "vulnerability": "Human confirmation for high-impact actions is component-configurable, not a structurally enforced gate.", + "impact": "Irreversible actions execute with no review opportunity, increasing the blast radius of any error or attack." + }, "mitigation": { "strategy": [ "require_human_approval", @@ -5565,7 +5761,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Greshake 2023", @@ -5661,6 +5857,13 @@ "untrusted_content" ] }, + "security_boundary": "reviewed artifact (declared manifest scope) → executed behavior (actual runtime access)", + "missing_control": "no scope enforcement at the agent-framework layer comparing runtime tool/resource calls against the component's own declared manifest", + "vulnerability_rationale": { + "capability": "Agent can invoke tools, APIs, files, or databases beyond what a skill's manifest declares as its required resource access.", + "vulnerability": "No runtime mechanism compares an agent's actual resource access against the manifest's declared scope. The manifest is a reviewed, trusted declaration; nothing enforces that declaration once the component runs.", + "impact": "The agent accesses resources beyond the component's declared scope, violating least privilege and possibly exposing sensitive data or systems that the user did not authorize." + }, "mitigation": { "strategy": [ "least_privilege", @@ -5704,7 +5907,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "CWE-269", @@ -5798,6 +6001,13 @@ "untrusted_content" ] }, + "security_boundary": "constraint binding (should be persistent) → context-window position (where it actually, and non-persistently, lives)", + "missing_control": "no mechanism keeps safety constraints binding independent of how much content has since entered the context", + "vulnerability_rationale": { + "capability": "Agent's effective attention to system-prompt and safety content can vary with context volume.", + "vulnerability": "Safety and system constraints have no persistence guarantee independent of their position in the context window; they can be positionally evicted rather than remaining structurally binding.", + "impact": "Safety constraints, user instructions and conversation history are pushed out of the context window, so the model may become more susceptible to subsequent malicious instructions." + }, "mitigation": { "strategy": [ "validate_input", @@ -5948,6 +6158,13 @@ "untrusted_content" ] }, + "security_boundary": "declared file extension → actual byte-level content", + "missing_control": "no content-type verification independent of the declared extension", + "vulnerability_rationale": { + "capability": "Skill files are loaded and trusted based on their declared extension.", + "vulnerability": "No content-type verification independent of the declared extension confirms the file's actual format before it's trusted.", + "impact": "Arbitrary executable content runs under the guise of a benign skill file, invisible to text-pattern scanners." + }, "mitigation": { "strategy": [ "validate_input", @@ -5992,7 +6209,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "CWE-434", @@ -6091,6 +6308,13 @@ "untrusted_content" ] }, + "security_boundary": "genuine session history (should be structurally distinct) → arbitrary content shaped to resemble history (currently indistinguishable to the model)", + "missing_control": "no structural or cryptographic separation between real history and content merely formatted to look like it", + "vulnerability_rationale": { + "capability": "Agent relies on conversation history to infer prior user intent and consent.", + "vulnerability": "No integrity or provenance check distinguishes genuine prior-turn history from content merely styled to resemble it within the current turn's context.", + "impact": "The agent believes the user previously approved an action, said something they did not, or established a precedent that does not exist, which enables social engineering of its decisions." + }, "mitigation": { "strategy": [ "validate_input", @@ -6134,7 +6358,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Greshake 2023", @@ -6228,6 +6452,13 @@ "external_comms" ] }, + "security_boundary": "tool-call parameters/return values → external transmission", + "missing_control": "monitoring inspects network destination, not tool-call payload content, for encoded sensitive data", + "vulnerability_rationale": { + "capability": "Agent can pass parameters to legitimate, already-authorized tools.", + "vulnerability": "No inspection of tool-call parameter or return content for encoded sensitive data.", + "impact": "Credential/PII/system-prompt exfiltration disguised as ordinary, legitimate-looking tool traffic." + }, "mitigation": { "strategy": [ "sanitize_output", @@ -6384,6 +6615,13 @@ "untrusted_content" ] }, + "security_boundary": "single-session, untrusted instruction → cross-session persistent behavior", + "missing_control": "no check on instructions that specifically target the agent's own persistence/memory behavior as their payload", + "vulnerability_rationale": { + "capability": "Agent's stated behavior can be shaped by instructions that ask it to \"remember\" something.", + "vulnerability": "No boundary prevents a single untrusted, single-session instruction from converting itself into cross-session persistent behavior via the agent's own compliance with a \"remember this\" directive.", + "impact": "A one-time injection becomes a persistent compromise: the instructions are re-applied in all future conversations, regardless of context resets, memory clears or new sessions." + }, "mitigation": { "strategy": [ "isolate_scope", @@ -6428,7 +6666,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Greshake 2023", @@ -6527,6 +6765,13 @@ "untrusted_content" ] }, + "security_boundary": "uploaded document content (should be data) → instruction", + "missing_control": "no boundary distinguishes uploaded document content from instruction the agent should follow", + "vulnerability_rationale": { + "capability": "Agent processes user-uploaded documents as part of a task.", + "vulnerability": "No boundary distinguishes uploaded document content from instruction the agent should follow.", + "impact": "Indirect prompt injection requiring only that a user be convinced to upload a crafted document." + }, "mitigation": { "strategy": [ "validate_input", @@ -6571,7 +6816,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-29T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Greshake 2023", @@ -6667,6 +6912,13 @@ "untrusted_content" ] }, + "security_boundary": "human visual review → model-level codepoint processing", + "missing_control": "no Unicode normalization/canonicalization check before human review", + "vulnerability_rationale": { + "capability": "Human reviewers evaluate text visually; the model processes Unicode codepoints.", + "vulnerability": "No canonicalization or normalization step reconciles what a human reviewer visually sees with what the model actually processes at the codepoint level.", + "impact": "Instructions that look innocuous to a human reviewer are processed as instructions by the model." + }, "mitigation": { "strategy": [ "validate_input", @@ -6818,6 +7070,13 @@ "untrusted_content" ] }, + "security_boundary": "claimed role → actually-verified role (never checked)", + "missing_control": "no authentication step backing role claims", + "vulnerability_rationale": { + "capability": "Skills can implement role-based access checks against user-supplied claims.", + "vulnerability": "Role-based access control is implemented by trusting a bare, self-asserted claim with no backing credential or authentication step.", + "impact": "Any user who simply claims the privileged role receives elevated access, bypassing all actual authentication." + }, "mitigation": { "strategy": [ "verify_identity", @@ -6968,6 +7227,13 @@ "untrusted_content" ] }, + "security_boundary": "agent-generated output → training/RLHF feedback signal", + "missing_control": "no integrity check on agent-generated feedback prevents the evaluated system from also controlling its own evaluation signal", + "vulnerability_rationale": { + "capability": "Agent-generated outputs can feed into a downstream training/RLHF feedback pipeline.", + "vulnerability": "No integrity check prevents the evaluated system from also controlling its own evaluation signal.", + "impact": "Gradual, hard-to-detect manipulation of future model behavior via biased reward signals." + }, "mitigation": { "strategy": [ "validate_input", @@ -7012,7 +7278,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Wan 2023", @@ -7111,6 +7377,13 @@ "untrusted_content" ] }, + "security_boundary": "declared task scope → actual network reachability", + "missing_control": "no network segmentation or egress scoping tied to a skill's declared purpose; the agent's network capability is all-or-nothing rather than scoped per task", + "vulnerability_rationale": { + "capability": "Agent has network connectivity or shell access sufficient to reach internal hosts and services.", + "vulnerability": "No network-layer segmentation or scope check restricts an agent's granted network capability to the destinations its declared task actually requires.", + "impact": "The attacker gains intelligence for further attacks (network scans, enumerated services, a map of internal infrastructure), all executed from a trusted internal host." + }, "mitigation": { "strategy": [ "least_privilege", @@ -7155,7 +7428,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "CWE-918", @@ -7419,6 +7692,13 @@ "external_comms" ] }, + "security_boundary": "external URL content → agent's full capability set", + "missing_control": "no identity/integrity verification gates dynamically-loaded code before execution", + "vulnerability_rationale": { + "capability": "Agent can dynamically load and execute code from a URL at runtime.", + "vulnerability": "No verification gates code loaded from an external URL before it executes with the agent's full capability set.", + "impact": "Full agent compromise via arbitrary attacker-controlled code with no static-review opportunity." + }, "mitigation": { "strategy": [ "pin_integrity", @@ -7463,7 +7743,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "CWE-829", @@ -7701,6 +7981,13 @@ "untrusted_content" ] }, + "security_boundary": "task-scoped credentials/access → reach beyond original task scope", + "missing_control": "no boundary prevents reuse of granted access to reach systems beyond the declared task", + "vulnerability_rationale": { + "capability": "Agent has network connectivity and credentials/tokens scoped to its current task.", + "vulnerability": "No boundary prevents that access from being reused to reach systems beyond the original task's authorized scope.", + "impact": "Compromise expands from one pipeline segment to adjacent systems the attacker could not reach directly." + }, "mitigation": { "strategy": [ "least_privilege", @@ -7745,7 +8032,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "MITRE ATT&CK T1021", @@ -7843,6 +8130,13 @@ "untrusted_content" ] }, + "security_boundary": "text-channel untrusted-content boundary (exists) → image-channel untrusted-content boundary (does not exist)", + "missing_control": "no cross-modal equivalent of existing text-content trust boundaries", + "vulnerability_rationale": { + "capability": "Multimodal agents can read text embedded in images.", + "vulnerability": "Untrusted-content handling boundaries exist for text but have no equivalent for text rendered inside images; the same class of content is trusted or untrusted depending on which modality carries it.", + "impact": "A prompt injection vector that completely bypasses text-level security scanning, because the malicious instruction is never present as text in the input stream, only as pixels in an image." + }, "mitigation": { "strategy": [ "validate_input", @@ -7887,7 +8181,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Qi 2023", @@ -7985,6 +8279,13 @@ "untrusted_content" ] }, + "security_boundary": "declared, bounded tool/delegation scope → actual, unbounded runtime use", + "missing_control": "no ceiling on tool invocations or sub-agent spawning, and no human checkpoint gating either, once a component's instructions grant \"unlimited\" authority", + "vulnerability_rationale": { + "capability": "Agent can use any declared tool and spawn sub-agents.", + "vulnerability": "No mechanism bounds how tool-use and sub-agent-spawning access is used once it is granted: there is no ceiling on invocations or spawning and no human checkpoint.", + "impact": "All scope boundaries and human oversight are removed, turning the agent into an unconstrained autonomous actor." + }, "mitigation": { "strategy": [ "least_privilege", @@ -8135,6 +8436,13 @@ "external_comms" ] }, + "security_boundary": "network-egress monitoring (exists) → content-level covert-channel monitoring (does not exist)", + "missing_control": "no content-level covert-channel detection independent of destination monitoring", + "vulnerability_rationale": { + "capability": "Agent output is reviewed by humans and monitored at the network layer.", + "vulnerability": "Exfiltration monitoring checks network destinations, not whether benign-looking output content itself encodes exfiltrated data; content-level exfiltration has no detection surface at all.", + "impact": "Sensitive data is exfiltrated through output that looks benign to a human reviewer, with no detection surface at the content level." + }, "mitigation": { "strategy": [ "sanitize_output", @@ -8441,6 +8749,13 @@ "external_comms" ] }, + "security_boundary": "tool result content (data) → code the agent generates and executes", + "missing_control": "no boundary prevents tool-result content from breaking out of data context into generated code", + "vulnerability_rationale": { + "capability": "Agent-generated orchestration code processes tool results in Code/REPL Mode.", + "vulnerability": "No boundary prevents tool result content from breaking out of data context into the code the agent generates and executes.", + "impact": "Arbitrary code execution bypassing all prompt-level, text-instruction filtering entirely." + }, "mitigation": { "strategy": [ "deny_by_default", @@ -8471,7 +8786,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-05-01T00:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "CWE-94", @@ -8598,6 +8913,13 @@ "untrusted_content" ] }, + "security_boundary": "rendered surface (what the user sees) → processed payload (what the model reads)", + "missing_control": "no consistency requirement between rendered and processed content from the same rich-UI payload", + "vulnerability_rationale": { + "capability": "MCP Apps can render rich UI elements the model also processes as context.", + "vulnerability": "No consistency check ensures what's rendered to the user matches what the model actually processes from the same payload.", + "impact": "Agent acts on instructions the user has no way to see, in an interface designed to look fully transparent." + }, "mitigation": { "strategy": [ "sanitize_output", @@ -8627,7 +8949,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-05-01T00:00:00Z", - "last_updated": "2026-08-29T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Greshake 2023", @@ -8755,6 +9077,13 @@ "external_comms" ] }, + "security_boundary": "low-trust server's instruction → high-trust server's capability, same session", + "missing_control": "no per-server trust isolation within a single multi-server agent session", + "vulnerability_rationale": { + "capability": "A single agent session can connect to and act on multiple MCP servers simultaneously.", + "vulnerability": "No per-server trust isolation prevents a low-trust server's instruction from directing the agent's use of a co-connected high-trust server.", + "impact": "Confused-deputy escalation from low-privilege compromise to high-privilege action." + }, "mitigation": { "strategy": [ "isolate_scope", @@ -8785,7 +9114,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-05-01T00:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "CWE-269", @@ -9193,6 +9522,13 @@ "external_comms" ] }, + "security_boundary": "agent-generated response content → client's automatic rendering (an unmonitored channel)", + "missing_control": "no inspection of response content for embedded exfiltration channels before client rendering acts on it", + "vulnerability_rationale": { + "capability": "Clients automatically render markdown/rich-content references in agent responses.", + "vulnerability": "No inspection of agent-generated response content for embedded exfiltration channels before automatic rendering fetches them.", + "impact": "Zero-interaction data exfiltration requiring no tool call and no obfuscation." + }, "mitigation": { "strategy": [ "sanitize_output", @@ -9218,7 +9554,7 @@ "researcher": "Aim Labs", "researcher_url": "https://arxiv.org/abs/2509.10540", "published": "2026-07-10T00:00:00Z", - "last_updated": "2026-08-09T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "CVE", @@ -9300,7 +9636,7 @@ "schema_version": "1.3.0", "status": "active", "published": "2026-07-14T00:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "component_type": "skill", "title": "Obfuscated or encoded skill payload designed to evade static scanners", "attack_class": "Obfuscation - Static Analysis Evasion", @@ -9334,6 +9670,13 @@ "untrusted_content" ] }, + "security_boundary": "as-scanned representation → as-executed representation", + "missing_control": "no decode-then-rescan step in the static-analysis pipeline", + "vulnerability_rationale": { + "capability": "Static scanners pattern-match against a skill's literal, as-written content.", + "vulnerability": "Static analysis operates on the encoded representation while execution operates on the decoded representation, with no decode-then-rescan step bridging the two.", + "impact": "Pattern-based and keyword-based static scanners fail to match the encoded form, while the decoded or executed form at runtime is fully malicious." + }, "mitigation": { "strategy": [ "validate_input", @@ -9688,6 +10031,13 @@ "private_data" ] }, + "security_boundary": "instruction-level review (exists) → configuration-level review (does not exist)", + "missing_control": "no requirement that safety-relevant config flags receive the same review rigor as instruction text", + "vulnerability_rationale": { + "capability": "Components can declare configuration flags controlling whether human approval is required.", + "vulnerability": "No requirement that safety-relevant configuration flags receive the same review scrutiny as instruction text.", + "impact": "A required human-in-the-loop control is silently removed with no instruction-level signal a reviewer would catch." + }, "mitigation": { "strategy": [ "deny_by_default", @@ -9710,7 +10060,7 @@ "kill_switch_active": false, "researcher": "hackerone.com/cantina_xyz", "published": "2026-07-27T00:00:00Z", - "last_updated": "2026-10-20T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "CVE-2026-33068 (GHSA-mmgp-wc2j-qcv7)", @@ -9804,6 +10154,13 @@ "untrusted_content" ] }, + "security_boundary": "passive action (opening a project) → code execution, no confirmation", + "missing_control": "no confirmation gate on auto-run behavior triggered passively rather than by explicit tool call", + "vulnerability_rationale": { + "capability": "IDE/dev-environment configuration can declare commands to run automatically on project load.", + "vulnerability": "No confirmation gate exists for auto-run behavior triggered by a passive action rather than an explicit tool call.", + "impact": "Code execution requiring no action beyond opening a compromised project directory." + }, "mitigation": { "strategy": [ "deny_by_default", @@ -9827,7 +10184,7 @@ "researcher": "Check Point Research (Aviv Donenfeld, Oded Vanunu)", "researcher_url": "https://research.checkpoint.com/2026/rce-and-api-token-exfiltration-through-claude-code-project-files-cve-2025-59536/", "published": "2026-07-27T00:00:00Z", - "last_updated": "2026-10-20T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Anthropic GHSA-ph6w-f82w-28w6", @@ -9948,6 +10305,13 @@ "external_comms" ] }, + "security_boundary": "model's own hallucinated belief → fetch/install action", + "missing_control": "no registry-existence or publisher-identity check before acting on a model-generated resource name", + "vulnerability_rationale": { + "capability": "Agent resolves user requests for well-known resources to package/repo/skill names it generates itself.", + "vulnerability": "No registry-existence or publisher-identity check occurs before fetching or installing a model-generated name.", + "impact": "Malware installation via a scalable, precomputed, cross-model squatting technique with no injection required at all." + }, "mitigation": { "strategy": [ "verify_identity", @@ -9972,7 +10336,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-08-02T00:00:00Z", - "last_updated": "2026-08-02T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Beware of Agentic Botnets (arXiv 2607.07433)", @@ -10077,6 +10441,13 @@ "entry_class": "tool_response", "payload_surface": "a benign, correct upstream skill's output (endorsement, audit finding, validation result) consumed by a downstream skill as an implicit trust or authorization signal" }, + "security_boundary": "upstream skill's output (benign) → downstream skill's trust signal (unverified)", + "missing_control": "no requirement that a downstream skill independently re-verify a trust claim carried in an upstream skill's output", + "vulnerability_rationale": { + "capability": "A downstream skill can consume another skill's output as part of its own decision logic.", + "vulnerability": "No requirement exists for a downstream skill to independently re-verify a trust or authorization claim in an upstream skill's output.", + "impact": "Harmful actions approved based on a spoofable trust credential no single skill's isolated review would ever catch." + }, "mitigation": { "strategy": [ "verify_identity", @@ -10101,7 +10472,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-08-02T00:00:00Z", - "last_updated": "2026-08-02T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Benign in Isolation, Harmful in Composition (arXiv 2606.15242)", @@ -10181,6 +10552,13 @@ "payload_surface": "shared OS/shell state (environment variables, file descriptors, working directory, temp files) connecting sequential CLI command executions within one agent session", "escalation": "instruction_to_capability" }, + "security_boundary": "single-command security review → multi-command behavioral effect; the boundary is the unit of analysis itself, per-command versus per-sequence", + "missing_control": "no cross-command state-flow analysis; every existing tool's unit of analysis stops at the single command", + "vulnerability_rationale": { + "capability": "Agent can issue sequences of CLI commands, none individually dangerous.", + "vulnerability": "No producer-consumer tracking across a command sequence within one session; every existing control (ShellCheck, GTFOBins, LOLBAS, single-command scanners) evaluates each command in isolation, so the composition itself is structurally invisible to them.", + "impact": "Benign-looking commands compose through shared operating-system state into a capability beyond what the user's task authorized, which no single-command check observes; published research reports a 96.59% attack success rate across 2,525 trials." + }, "mitigation": { "strategy": [ "isolate_scope", @@ -10205,7 +10583,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-08-02T00:00:00Z", - "last_updated": "2026-08-02T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "MOSAIC (arXiv 2607.02857)", @@ -10289,6 +10667,13 @@ "payload_surface": "an image resource bundled within the skill package, distinct from the package's documentation, manifest, or source code text", "escalation": "data_to_instruction" }, + "security_boundary": "text-only review pipeline → bundled image resource (never decoded for review)", + "missing_control": "no visual/multimodal decoding step exists in static review", + "vulnerability_rationale": { + "capability": "Multimodal agents can decode and act on bundled image content within a skill package.", + "vulnerability": "No visual/multimodal decoding step exists in the text-only static-review pipeline covering the rest of the package.", + "impact": "Instructions invisible to every current text-based scanner execute once a multimodal agent processes the resource." + }, "mitigation": { "strategy": [ "validate_input", @@ -10313,7 +10698,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-08-02T00:00:00Z", - "last_updated": "2026-08-02T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "SkillCamo (arXiv 2606.18198)", @@ -10408,6 +10793,13 @@ "external_comms" ] }, + "security_boundary": "dormant, per-agent fragments → externally reassembled, post-hoc payload", + "missing_control": "no anomaly detection for encoded fragments inconsistent with a tool's stated function, and no cross-agent correlation of dormant fragments", + "vulnerability_rationale": { + "capability": "Tools deliver observations to agents that persist in memory/context after the call.", + "vulnerability": "No anomaly detection or cross-agent correlation catches a fragmented payload no single session could ever contain enough of to detect.", + "impact": "A complete backdoor exists and becomes executable only after the fact, entirely outside any single session's visibility." + }, "mitigation": { "strategy": [ "provenance_label", @@ -10432,7 +10824,7 @@ "researcher": "Pengyu Zhu, Lijun Li, Yaxing Lyu, Li Sun, Sen Su, Jing Shao", "researcher_url": "https://arxiv.org/abs/2510.11246", "published": "2026-08-02T00:00:00Z", - "last_updated": "2026-08-23T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Collaborative Shadows (arXiv 2510.11246)", @@ -10531,6 +10923,13 @@ "external_comms" ] }, + "security_boundary": "expected local daemon → actual, redirected remote daemon (unverified)", + "missing_control": "no verification that a declared daemon target matches the expected local daemon before build/run/pull proceeds", + "vulnerability_rationale": { + "capability": "Components can declare a container daemon connection target via configuration.", + "vulnerability": "No verification confirms a declared daemon target is the expected local daemon before operations proceed against it.", + "impact": "Secrets and bind-mounted data are exposed to whatever infrastructure actually receives the redirected connection." + }, "mitigation": { "strategy": [ "deny_by_default", @@ -10555,7 +10954,7 @@ "researcher": "Nicolai (predictor2718)", "researcher_url": "https://github.com/predictor2718", "published": "2026-08-06T00:00:00Z", - "last_updated": "2026-08-06T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "cfgaudit crosswalk gap detail", @@ -11057,6 +11456,13 @@ "untrusted_content" ] }, + "security_boundary": "steering text (targets the checker) → classifier's approve/deny judgment", + "missing_control": "no boundary prevents the same class of natural-language content that steers a primary agent from also steering the classifier meant to check it", + "vulnerability_rationale": { + "capability": "A committed configuration file can declare natural-language steering text consumed by a safety-classifier subagent.", + "vulnerability": "No boundary prevents natural-language content from probabilistically steering the classifier meant to check an agent's actions, the same way it steers the agent itself.", + "impact": "Auto-approval of shell/MCP/Fetch calls the classifier would otherwise flag, via a committed repository file." + }, "mitigation": { "strategy": [ "require_human_approval", @@ -11083,7 +11489,7 @@ "researcher": "Nicolai (predictor2718)", "researcher_url": "https://github.com/predictor2718", "published": "2026-08-08T00:00:00Z", - "last_updated": "2026-08-08T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "predictor2718 PR #123", @@ -12514,6 +12920,13 @@ "entry_class": "content", "payload_surface": "skill instruction body: false-authority framing" }, + "security_boundary": "claimed identity (asserted in content) → actual, verifiable identity (not checked against anything)", + "missing_control": "no authentication of in-band identity/authority claims", + "vulnerability_rationale": { + "capability": "Agent can act on authority claims present in content it processes.", + "vulnerability": "No mechanism authenticates in-content authority claims; any content can assert arbitrary authority with no verification step.", + "impact": "The agent follows instructions it would otherwise question, because it defers to the claimed authority within its trust hierarchy." + }, "mitigation": { "strategy": [ "verify_identity", @@ -12536,7 +12949,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-20T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "CWE-290", @@ -12618,7 +13031,7 @@ "schema_version": "1.3.0", "status": "active", "published": "2026-07-14T00:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "component_type": "skill", "title": "Deceptive skill trigger or activation-scope manipulation via misleading manifest description", "attack_class": "Social Engineering - Trigger Scope Deception", @@ -12652,6 +13065,13 @@ "untrusted_content" ] }, + "security_boundary": "declared manifest trigger/description → actual implemented behavior", + "missing_control": "no verification that declared triggers match real behavior before invocation decisions are made", + "vulnerability_rationale": { + "capability": "A skill's declared manifest trigger/description determines when it gets invoked.", + "vulnerability": "No verification checks that a declared trigger matches the skill's actual implemented behavior before invocation.", + "impact": "Over-broad or implicit invocation in contexts the skill's real behavior does not warrant." + }, "mitigation": { "strategy": [ "validate_input", diff --git a/dist/ave-records-latest.manifest.json b/dist/ave-records-latest.manifest.json index 57089bf..7504000 100644 --- a/dist/ave-records-latest.manifest.json +++ b/dist/ave-records-latest.manifest.json @@ -1,7 +1,7 @@ { "schema_version": "1.3.0", "record_count": 89, - "generated_at": "2026-10-31T09:53:39.110Z", + "generated_at": "2026-10-31T14:48:01.286Z", "source": "https://github.com/aveproject/ave", - "sha256": "f059df01e9e307840623f2e5ada880f42c6529c87eb4806ff3cced319765e153" + "sha256": "2ddd54c181615e2e4fe07fb902b5169b9396ec10a61fe7bc05cface2c411549c" } diff --git a/dist/ave-taxonomy-latest.json b/dist/ave-taxonomy-latest.json new file mode 100644 index 0000000..f324a68 --- /dev/null +++ b/dist/ave-taxonomy-latest.json @@ -0,0 +1,1531 @@ +{ + "guid": "5110b285-34d7-5334-94db-0308b24cfb49", + "name": "AVE", + "fullName": "Agentic Vulnerability Enumeration", + "organization": "AVE Project", + "product": "AVE", + "informationUri": "https://aveproject.org", + "shortDescription": { + "text": "Agentic Vulnerability Enumeration: behavioral vulnerability classes for agentic AI components" + }, + "language": "en", + "contents": [ + "nonLocalizedData" + ], + "isComprehensive": true, + "taxa": [ + { + "id": "AVE-2026-00001", + "name": "Metamorphic payload via external config fetch", + "shortDescription": { + "text": "Supply Chain - Metamorphic Payload" + }, + "fullDescription": { + "text": "Component contains instructions to fetch and execute remote content, replacing its own behavioral instructions at runtime." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00001", + "properties": { + "status": "active", + "severity": "HIGH", + "aivss_score": 8, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00002", + "name": "MCP tool description behavioral injection", + "shortDescription": { + "text": "Prompt Injection - Tool Description" + }, + "fullDescription": { + "text": "MCP tool description field contains directives targeting agent behavior rather than describing tool functionality." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00002", + "properties": { + "status": "active", + "severity": "HIGH", + "aivss_score": 7.3, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00003", + "name": "Credential exfiltration via agent instruction", + "shortDescription": { + "text": "Data Exfiltration - Credential Theft" + }, + "fullDescription": { + "text": "Component instructs agent to read and transmit environment variables, API keys, or other credentials to an external destination." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00003", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 6.8, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00004", + "name": "Arbitrary code execution via shell pipe injection in agentic component", + "shortDescription": { + "text": "Tool Abuse - Shell Pipe Injection" + }, + "fullDescription": { + "text": "Component instructs the agent to pipe remote content into a shell interpreter (curl|bash, wget|sh, eval(requests.get(...)))." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00004", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 5.9, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00005", + "name": "Recursive file system destruction via destructive command injection in agentic component", + "shortDescription": { + "text": "Tool Abuse - Destructive Command" + }, + "fullDescription": { + "text": "Component instructs the agent to execute recursive deletion commands on broad filesystem paths or system directories." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00005", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 5.6, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00006", + "name": "Cryptocurrency wallet drain via malicious fund transfer instruction in agentic component", + "shortDescription": { + "text": "Tool Abuse - Cryptocurrency Drain" + }, + "fullDescription": { + "text": "Component instructs agent to transfer all funds, approve unlimited token allowance, or sign a transaction to an externally supplied address." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00006", + "properties": { + "status": "active", + "severity": "HIGH", + "aivss_score": 7.5, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00007", + "name": "Agent goal hijack via direct instruction override in agentic component", + "shortDescription": { + "text": "Prompt Injection - Goal Hijack" + }, + "fullDescription": { + "text": "Component contains explicit instruction-override language directing the agent to abandon its current task and follow new instructions from the component." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00007", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 6.1, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00008", + "name": "Agent persistence via self-replication instruction in agentic component", + "shortDescription": { + "text": "Persistence - Self-Replication" + }, + "fullDescription": { + "text": "Component instructs the agent to write to startup scripts, schedule itself via cron, or copy itself to directories that execute on login or reboot." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00008", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 6.3, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00009", + "name": "AI identity jailbreak via role-play or persona override in agentic component", + "shortDescription": { + "text": "Prompt Injection - Jailbreak" + }, + "fullDescription": { + "text": "Component instructs the agent to pretend to be a different AI, adopt a persona without safety constraints, or activate a fictional unrestricted mode." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00009", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 5.5, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00010", + "name": "Covert instruction concealment via secrecy directive in agentic component", + "shortDescription": { + "text": "Prompt Injection - Hidden Instruction" + }, + "fullDescription": { + "text": "Component instructs the agent to not reveal, disclose, or acknowledge these instructions to the user or operator." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00010", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 5.6, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00011", + "name": "Arbitrary tool invocation via dynamic tool call injection in agentic component", + "shortDescription": { + "text": "Tool Abuse - Dynamic Tool Call" + }, + "fullDescription": { + "text": "Component contains explicit tool invocation directives with specific parameters the agent must pass, bypassing the agent's own tool selection logic." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00011", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 5.7, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00012", + "name": "Capability escalation via false permission grant in agentic component", + "shortDescription": { + "text": "Privilege Escalation - Permission Grant" + }, + "fullDescription": { + "text": "Component asserts that elevated permissions have been granted to the agent, claiming authority to override normal operational boundaries." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00012", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 4.5, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00013", + "name": "Personal data exfiltration via PII collection and transmission in agentic component", + "shortDescription": { + "text": "Data Exfiltration - PII Theft" + }, + "fullDescription": { + "text": "Component instructs the agent to collect PII fields (name, email, phone, address, SSN, passport, credit card) and transmit or store them externally." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00013", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 6.5, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00014", + "name": "False authority claim via trust escalation impersonation in agentic component", + "shortDescription": { + "text": "Social Engineering - Trust Escalation" + }, + "fullDescription": { + "text": "Component claims to be a message from Anthropic, OpenAI, Google, Microsoft, or the developer/operator to establish false authority over the agent." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00014", + "properties": { + "status": "active", + "severity": "LOW", + "aivss_score": 3.7, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00015", + "name": "System prompt extraction via direct interrogation instruction in agentic component", + "shortDescription": { + "text": "Information Disclosure - System Prompt Leak" + }, + "fullDescription": { + "text": "Component instructs the agent to reveal, output, or repeat its system prompt, instructions, configuration, or internal guidelines." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00015", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 4.9, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00016", + "name": "Indirect Prompt Injection via RAG Retrieval", + "shortDescription": { + "text": "Prompt Injection - RAG Retrieval" + }, + "fullDescription": { + "text": "Component embeds malicious instructions in content indexed by a RAG pipeline, causing the agent to execute attacker-controlled instructions when that content is retrieved." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00016", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 6.4, + "detection_stage": "runtime_observed" + } + }, + { + "id": "AVE-2026-00017", + "name": "MCP Server Impersonation or Spoofing", + "shortDescription": { + "text": "Supply Chain - Server Impersonation" + }, + "fullDescription": { + "text": "Component falsely claims to be an official, verified, or trusted MCP server to gain elevated trust or bypass agent-level permission checks." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00017", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 5.7, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00018", + "name": "Tool Result Manipulation or Output Poisoning", + "shortDescription": { + "text": "Tool Abuse - Result Manipulation" + }, + "fullDescription": { + "text": "Component instructs the agent to modify, fabricate, or suppress tool call results before reporting them to the user or passing them to downstream components." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00018", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 4.4, + "detection_stage": "runtime_observed" + } + }, + { + "id": "AVE-2026-00019", + "name": "Agent Memory Poisoning", + "shortDescription": { + "text": "Persistence - Memory Poisoning" + }, + "fullDescription": { + "text": "Component writes malicious instructions or false facts into the agent's persistent memory store, causing the agent to act on attacker-controlled beliefs in future conversations." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00019", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 5.6, + "detection_stage": "runtime_observed" + } + }, + { + "id": "AVE-2026-00020", + "name": "Cross-Agent Prompt Injection (A2A)", + "shortDescription": { + "text": "Prompt Injection - Cross-Agent A2A" + }, + "fullDescription": { + "text": "Component embeds instructions targeting a secondary agent in a multi-agent pipeline, causing the downstream agent to perform actions not intended by the orchestrating agent or user." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00020", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 5.9, + "detection_stage": "runtime_observed" + } + }, + { + "id": "AVE-2026-00021", + "name": "Autonomous Action Without User Confirmation", + "shortDescription": { + "text": "Prompt Injection - Human-in-Loop Bypass" + }, + "fullDescription": { + "text": "Component instructs the agent to take irreversible or high-impact actions without requesting user confirmation, removing the human from the decision loop." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00021", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 4.5, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00022", + "name": "Scope Creep - Accessing Undeclared Resources", + "shortDescription": { + "text": "Privilege Escalation - Scope Creep" + }, + "fullDescription": { + "text": "Component instructs the agent to access files, APIs, databases, or systems that were not declared in the component's manifest or authorised by the user." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00022", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 6, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00023", + "name": "Model Context Window Manipulation", + "shortDescription": { + "text": "Prompt Injection - Context Window Manipulation" + }, + "fullDescription": { + "text": "Component instructs agent to repeat, pad, or generate large volumes of content with the intent of overflowing the context window." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00023", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 5.8, + "detection_stage": "runtime_observed" + } + }, + { + "id": "AVE-2026-00024", + "name": "Supply Chain - Content Type Mismatch (Magika)", + "shortDescription": { + "text": "Supply Chain - Content Type Mismatch" + }, + "fullDescription": { + "text": "A file's actual content type does not match its declared extension. An ELF binary, Windows executable, Python pickle, PHP script, or other executable content is disguised as a benign skill file." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00024", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 6.8, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00025", + "name": "Conversation History Injection", + "shortDescription": { + "text": "Prompt Injection - Conversation History" + }, + "fullDescription": { + "text": "Component embeds fake prior conversation history to manipulate the agent's understanding of what the user previously said, consented to, or approved." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00025", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 4.5, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00026", + "name": "Exfiltration via Tool Output Encoding", + "shortDescription": { + "text": "Data Exfiltration - Output Encoding" + }, + "fullDescription": { + "text": "Component instructs agent to encode sensitive data (credentials, keys, PII) inside tool call parameters for covert exfiltration." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00026", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 6.8, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00027", + "name": "Multi-Turn Attack - Instruction Persistence Across Conversations", + "shortDescription": { + "text": "Prompt Injection - Multi-Turn Persistence" + }, + "fullDescription": { + "text": "Component instructs the agent to retain and re-apply malicious instructions across multiple conversation turns, surviving memory resets or context window rollovers." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00027", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 5.6, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00028", + "name": "Prompt Injection via File or Document Content", + "shortDescription": { + "text": "Prompt Injection - File Content" + }, + "fullDescription": { + "text": "Component instructs the agent to execute instructions embedded in user-supplied files, documents, or images, enabling indirect prompt injection through untrusted content." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00028", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 5.9, + "detection_stage": "runtime_observed" + } + }, + { + "id": "AVE-2026-00029", + "name": "Homoglyph or Unicode Obfuscation Attack", + "shortDescription": { + "text": "Obfuscation - Unicode Homoglyph" + }, + "fullDescription": { + "text": "Skill file contains zero-width characters, bidirectional override codes, or Cyrillic homoglyphs used to conceal instructions from human reviewers." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00029", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 4.8, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00030", + "name": "Privilege Escalation via False Role Claim", + "shortDescription": { + "text": "Privilege Escalation - False Role Claim" + }, + "fullDescription": { + "text": "Component instructs the agent to grant elevated privileges when a user or external party falsely claims a privileged role (admin, root, operator), effectively implementing a privilege escalation backdoor." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00030", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 4.3, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00031", + "name": "Training Data or Feedback Loop Poisoning", + "shortDescription": { + "text": "Persistence - Feedback Loop Poisoning" + }, + "fullDescription": { + "text": "Component instructs the agent to generate outputs designed to corrupt training pipelines, feedback loops, or RLHF reward signals to manipulate future model behaviour." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00031", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 5.4, + "detection_stage": "runtime_observed" + } + }, + { + "id": "AVE-2026-00032", + "name": "Network Reconnaissance Instruction", + "shortDescription": { + "text": "Reconnaissance - Internal Network Scanning" + }, + "fullDescription": { + "text": "Component instructs the agent to probe internal network topology, scan ports, enumerate services, or map infrastructure beyond the declared scope of the skill." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00032", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 4, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00033", + "name": "Unsafe Deserialization or Eval Instruction", + "shortDescription": { + "text": "Tool Abuse - Unsafe Deserialization" + }, + "fullDescription": { + "text": "Component instructs agent to deserialize untrusted input or evaluate dynamic code from external sources." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00033", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 4.2, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00034", + "name": "Supply Chain - Dynamic Third-Party Skill Import", + "shortDescription": { + "text": "Supply Chain - Dynamic Skill Import" + }, + "fullDescription": { + "text": "Component instructs the agent to dynamically load, import, or install a third-party skill, plugin, or tool from an unverified external URL or source at runtime, enabling supply chain compromise." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00034", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 6.6, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00035", + "name": "Environment or Sensor Data Manipulation", + "shortDescription": { + "text": "Manipulation - Sensor Data Poisoning" + }, + "fullDescription": { + "text": "Component instructs the agent to fabricate, alter, or suppress sensor readings, environment observations, or system state reports to deceive operators or downstream agents." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00035", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 4.2, + "detection_stage": "runtime_observed" + } + }, + { + "id": "AVE-2026-00036", + "name": "Lateral Movement - Pivot to Other Systems", + "shortDescription": { + "text": "Lateral Movement - Agent Pivot" + }, + "fullDescription": { + "text": "Component instructs the agent to use access gained in the current context to connect to, enumerate, or attack other systems, services, or agents not within the original authorised scope." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00036", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 5.9, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00037", + "name": "Prompt Injection via Image or Vision Input", + "shortDescription": { + "text": "Prompt Injection - Multimodal Vision" + }, + "fullDescription": { + "text": "Component instructs the agent to execute instructions found in images, screenshots, or visual content, enabling prompt injection through multimodal inputs that bypass text-level security filters." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00037", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 5.1, + "detection_stage": "runtime_observed" + } + }, + { + "id": "AVE-2026-00038", + "name": "Excessive Agency - Unbounded Tool Use or Sub-Agent Spawning", + "shortDescription": { + "text": "Tool Abuse - Unbounded Tool Use" + }, + "fullDescription": { + "text": "Component instructs agent to use any available tool, spawn unlimited sub-agents, or recursively expand its capabilities without scope or oversight." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00038", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 5.9, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00039", + "name": "Covert Channel - Steganographic Data Exfiltration", + "shortDescription": { + "text": "Data Exfiltration - Covert Channel" + }, + "fullDescription": { + "text": "Component instructs agent to encode sensitive data in output formatting, first-letter patterns, whitespace, or timing to create a covert exfiltration channel." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00039", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 4.9, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00040", + "name": "Insecure Output - Unescaped Injection into Downstream System", + "shortDescription": { + "text": "Tool Abuse - Insecure Output Handling" + }, + "fullDescription": { + "text": "Component instructs agent to pass user input or LLM output directly into SQL queries, HTML templates, or shell commands without escaping or sanitisation." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00040", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 5.4, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00041", + "name": "Prompt injection via MCP server-card tool descriptions before agent makes first call", + "shortDescription": { + "text": "Prompt Injection - MCP Server-Card Injection" + }, + "fullDescription": { + "text": "Tool descriptions in the server-card contain behavioral instructions targeting the agent - IMPORTANT/WARNING/NOTE prefixes, before/after calling directives, or instructions to perform actions not related to the tool's declared function." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00041", + "properties": { + "status": "active", + "severity": "HIGH", + "aivss_score": 8.2, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00042", + "name": "Payload injection into agent-generated orchestration code via poisoned tool results in REPL/Code Mode", + "shortDescription": { + "text": "Prompt Injection - REPL Code Mode Payload Injection" + }, + "fullDescription": { + "text": "Skill instructs agent to pass tool results directly into eval(), exec(), or dynamically constructed code strings. Tool result content contains code fragments, escape sequences, or string terminators designed to break out of data context into code context." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00042", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 4.7, + "detection_stage": "runtime_observed" + } + }, + { + "id": "AVE-2026-00043", + "name": "Prompt injection via rich UI payload (canvas, artifact, form) rendered by MCP App", + "shortDescription": { + "text": "Prompt Injection - MCP App UI Payload Injection" + }, + "fullDescription": { + "text": "Rich UI payload (canvas, artifact, SVG, HTML) contains prompt injection instructions in non-rendered elements - hidden divs, alt attributes, aria-labels, SVG metadata, HTML comments, or zero-width characters - that the model processes but the user does not see." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00043", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 4.7, + "detection_stage": "runtime_observed" + } + }, + { + "id": "AVE-2026-00044", + "name": "Prompt injection via poisoned async task result injected into future agent context", + "shortDescription": { + "text": "Prompt Injection - Async Task Result Poisoning" + }, + "fullDescription": { + "text": "Agent reads async task results from an external queue, webhook, or polling endpoint without validating that result content is data - not instructions. Result payload contains imperative language or structured injection patterns targeting the agent's next action." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00044", + "properties": { + "status": "active", + "severity": "HIGH", + "aivss_score": 8.1, + "detection_stage": "runtime_observed" + } + }, + { + "id": "AVE-2026-00045", + "name": "Privilege escalation via cross-app-access - pivot from low-trust to high-trust MCP server using shared agent session", + "shortDescription": { + "text": "Privilege Escalation - Cross-App-Access Escalation" + }, + "fullDescription": { + "text": "A tool description or result from a low-trust MCP server instructs the agent to use tools from a different, higher-trust MCP server connected in the same session. The instruction crosses server trust boundaries using the agent as a confused deputy." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00045", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 6.4, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00046", + "name": "MCP tool hook hijacking - redirect tool execution to attacker-controlled callback", + "shortDescription": { + "text": "Execution Hijack - Tool Hook Interception" + }, + "fullDescription": { + "text": "Skill instructs agent to register a hook, callback, or interceptor on tool execution. The hook targets all tool calls or a broad class of tools and routes them through an external URL or attacker-controlled handler before the legitimate tool runs." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00046", + "properties": { + "status": "active", + "severity": "CRITICAL", + "aivss_score": 9.2, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00047", + "name": "Hardcoded credentials in agent component - API keys and secrets exposed in skill files", + "shortDescription": { + "text": "Sensitive Data Exposure - Hardcoded Credentials" + }, + "fullDescription": { + "text": "Skill file contains a high-entropy string adjacent to a credential keyword such as api_key, secret, token, password, or a known key format prefix such as sk- or Bearer. The credential is a literal value, not an environment variable reference or secrets manager path." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00047", + "properties": { + "status": "active", + "severity": "HIGH", + "aivss_score": 7.6, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00048", + "name": "Unsafe agent delegation chain - sub-agent spawned with inherited permissions and no trust boundary", + "shortDescription": { + "text": "Privilege Escalation - Unsafe Agent Delegation" + }, + "fullDescription": { + "text": "Skill instructs agent to spawn a sub-agent or delegate a task to another agent without specifying an explicit tool allowlist or permission scope for the sub-agent. The delegation instruction uses language such as full access, inherit your permissions, or grant all tools." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00048", + "properties": { + "status": "active", + "severity": "HIGH", + "aivss_score": 7.7, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00049", + "name": "HTTP Host Header Injection via Agent-Initiated Request (BadHost)", + "shortDescription": { + "text": "Supply Chain - HTTP Header Injection" + }, + "fullDescription": { + "text": "Component sets or overwrites the HTTP Host header on outbound requests to a value that does not match the declared target endpoint's natural host. The injected host points to attacker infrastructure. Pattern also manifests as X-Forwarded-Host, X-Original-URL, or Forwarded header manipulation that causes server-side request routing to an unintended destination." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00049", + "properties": { + "status": "active", + "severity": "HIGH", + "aivss_score": 7.2, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00050", + "name": "Parasitic Toolchain — Silent Tool Registration and Persistent Hook Injection", + "shortDescription": { + "text": "Persistence - Parasitic Toolchain" + }, + "fullDescription": { + "text": "Component registers tool handlers or hooks beyond its declared manifest scope during session initialization. The registration extends the component's footprint into the agent's tool dispatch layer, granting it visibility into or control over calls intended for other tools. The parasitic tools appear as first-class registered tools, not obviously distinguishable from legitimately registered ones." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00050", + "properties": { + "status": "active", + "severity": "HIGH", + "aivss_score": 7.2, + "detection_stage": "runtime_observed" + } + }, + { + "id": "AVE-2026-00051", + "name": "OAuth Discovery Rebinding — Authorization Endpoint Redirected to Attacker Server", + "shortDescription": { + "text": "Supply Chain - OAuth Discovery Rebinding" + }, + "fullDescription": { + "text": "MCP server's OAuth discovery metadata document returns authorization_endpoint, token_endpoint, or jwks_uri values whose host component does not match the server's own declared origin or a pre-approved authorization server domain. The mismatch causes the agent to initiate OAuth flows against an attacker-controlled endpoint." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00051", + "properties": { + "status": "active", + "severity": "HIGH", + "aivss_score": 7.2, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00052", + "name": "Command injection via unsanitized tool-call parameter in MCP server implementation", + "shortDescription": { + "text": "Tool Abuse - Implementation Command Injection" + }, + "fullDescription": { + "text": "MCP tool handler code passes a caller-supplied tool-call parameter value directly into a shell or system-command execution function without sanitization, executing arbitrary OS commands under the server process's privileges -- independent of any agent instruction or prompt content." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00052", + "properties": { + "status": "active", + "severity": "HIGH", + "aivss_score": 7.5, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00053", + "name": "Path traversal via unsanitized path parameter in MCP resource/file-handler implementation", + "shortDescription": { + "text": "Tool Abuse - Resource Path Traversal" + }, + "fullDescription": { + "text": "MCP resource or file-handler tool's own path-validation code fails to canonicalize and contain a caller-supplied path or URL parameter, allowing directory-traversal sequences to read or write files and resources outside the tool's declared scope." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00053", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 6.3, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00054", + "name": "Code-execution sandbox escape via JavaScript prototype-chain traversal", + "shortDescription": { + "text": "Execution Hijack - Code Execution Sandbox Escape" + }, + "fullDescription": { + "text": "A code-execution tool's sandbox fails to contain a submitted payload that uses prototype-chain traversal to reach the host JavaScript or Python runtime, achieving code execution with host-level privileges outside the tool's declared execution boundary." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00054", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 6.7, + "detection_stage": "runtime_observed" + } + }, + { + "id": "AVE-2026-00055", + "name": "Command execution via untrusted MCP server launch configuration (STDIO)", + "shortDescription": { + "text": "Supply Chain - MCP STDIO Launch Configuration Injection" + }, + "fullDescription": { + "text": "An MCP client spawns a server as a STDIO subprocess using command and args fields taken directly from configuration or registry data with no validation, executing arbitrary OS commands under the client's privileges before any MCP protocol handshake occurs." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00055", + "properties": { + "status": "active", + "severity": "HIGH", + "aivss_score": 7.7, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00056", + "name": "Zero-click data exfiltration via markdown image auto-fetch in agent response", + "shortDescription": { + "text": "Data Exfiltration - Rendered Content Auto-Fetch" + }, + "fullDescription": { + "text": "Agent-generated response embeds a plain markdown image or link reference carrying sensitive data in its URL; the client's automatic rendering behavior fetches that URL, exfiltrating the data with no tool call, no obfuscation, and no further user interaction." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00056", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 5.8, + "detection_stage": "runtime_observed" + } + }, + { + "id": "AVE-2026-00057", + "name": "Obfuscated or encoded skill payload designed to evade static scanners", + "shortDescription": { + "text": "Obfuscation - Static Analysis Evasion" + }, + "fullDescription": { + "text": "Component contains base64, hex, or similarly encoded strings that decode to instruction-like or executable content at runtime, or splits scanner-relevant keywords across string concatenation or variable interpolation to avoid single-pass static pattern matches." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00057", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 4.4, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00058", + "name": "Deceptive skill trigger or activation-scope manipulation via misleading manifest description", + "shortDescription": { + "text": "Social Engineering - Trigger Scope Deception" + }, + "fullDescription": { + "text": "Skill manifest declares trigger keywords or a description disproportionately broad relative to its actual narrow function, or promises generic utility while its implementation performs a specific, sensitive action, causing over-broad or implicit invocation." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00058", + "properties": { + "status": "active", + "severity": "LOW", + "aivss_score": 3.1, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00059", + "name": "Fragmented cross-description prompt injection reassembled at a planted trigger (ShareLock-class)", + "shortDescription": { + "text": "Prompt Injection - Fragmented Cross-Description Reassembly" + }, + "fullDescription": { + "text": "Tool descriptions across multiple tools each carry an individually benign-looking fragment of a larger instruction. A separately planted trigger, commonly introduced during a server update, causes the model to reassemble the fragments into a complete, actionable instruction at inference time, after tool discovery and before any tool call." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00059", + "properties": { + "status": "active", + "severity": "HIGH", + "aivss_score": 7.1, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00060", + "name": "STDIO transport shell injection via unsanitized tool call parameters", + "shortDescription": { + "text": "Remote Code Execution - STDIO Transport Shell Injection" + }, + "fullDescription": { + "text": "Tool call parameters containing shell metacharacters (backticks, pipes, semicolons, command substitution syntax) are passed to a host shell without escaping or parameterization, resulting in execution of attacker-controlled shell commands rather than the parameter being treated as inert string data." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00060", + "properties": { + "status": "active", + "severity": "HIGH", + "aivss_score": 7.2, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00061", + "name": "TLS certificate verification disabled in agent component configuration", + "shortDescription": { + "text": "Insecure Configuration - TLS Verification Disabled" + }, + "fullDescription": { + "text": "Configuration explicitly sets a TLS verification bypass flag (verify=False, rejectUnauthorized: false, or equivalent) for the component's own outbound network calls, rather than relying on default, enforced certificate validation." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00061", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 4.1, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00062", + "name": "Unpinned dependency version allowing supply chain substitution", + "shortDescription": { + "text": "Supply Chain - Unpinned Dependency Substitution" + }, + "fullDescription": { + "text": "A component's declared dependency references a mutable version specifier (a floating tag, a version range with no upper bound, an unpinned package name with no hash or lockfile entry) rather than a specific, content-addressed or exact-version reference." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00062", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 4.4, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00063", + "name": "Human approval gate bypassed via declarative configuration, distinct from AVE-2026-00048", + "shortDescription": { + "text": "Privilege Escalation - Approval Gate Bypass Configuration" + }, + "fullDescription": { + "text": "Configuration sets a declarative flag (auto_approve, skip_confirmation, require_approval: false, or equivalent) that removes a human-in-the-loop check for high-risk actions, present in config rather than in instruction text, and therefore invisible to a review process that only inspects a component's stated instructions." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00063", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 4.8, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00064", + "name": "Zero-click code execution via project-load auto-run configuration", + "shortDescription": { + "text": "Remote Code Execution - Zero-Click Auto-Run Configuration" + }, + "fullDescription": { + "text": "A project-level configuration file declares a command or script to execute automatically on project load or open, with no corresponding user confirmation step, distinct from a tool call the model or user explicitly initiates." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00064", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 5.2, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00065", + "name": "A2A agent card poisoning via embedded adversarial instructions", + "shortDescription": { + "text": "Prompt Injection - A2A Agent Card Poisoning" + }, + "fullDescription": { + "text": "A remote agent's A2A agent card contains embedded natural-language instructions disguised as capability descriptions or operational metadata, which the receiving agent's reasoning context treats as authoritative once the card is loaded during discovery or delegation planning, before any explicit task exchange occurs." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00065", + "properties": { + "status": "active", + "severity": "HIGH", + "aivss_score": 7.1, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00066", + "name": "Hallucinated skill-name squatting (HalluSquatting)", + "shortDescription": { + "text": "Supply Chain - Hallucinated Resource Squatting" + }, + "fullDescription": { + "text": "Agent resolves a user's request referencing a well-known or trending resource to a package, repository, or skill name absent from any verified registry the request could plausibly resolve to, then fetches or installs content from that unverified name without a registry-existence or publisher-identity check." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00066", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 6.2, + "detection_stage": "runtime_observed" + } + }, + { + "id": "AVE-2026-00067", + "name": "Skill composition trust transfer: an upstream skill's output silently becomes a downstream skill's trust signal", + "shortDescription": { + "text": "Privilege Escalation - Skill Composition Trust Transfer" + }, + "fullDescription": { + "text": "A downstream skill accepts an upstream skill's output (an endorsement, an audit result, a validation finding, or similar artifact) as sufficient authorization or trust justification for a sensitive action, without independently re-verifying the claim the upstream output represents." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00067", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 5, + "detection_stage": "runtime_observed" + } + }, + { + "id": "AVE-2026-00068", + "name": "CLI command composition risk: benign commands compose through shared shell state into unauthorized capability", + "shortDescription": { + "text": "Tool Abuse - CLI Command Composition" + }, + "fullDescription": { + "text": "A command sequence issued by an agent contains no single command that is independently dangerous, but an earlier command's output, environment modification, or file artifact is consumed by a later command in the same sequence to produce a capability or effect the task did not authorize." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00068", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 5.1, + "detection_stage": "runtime_observed" + } + }, + { + "id": "AVE-2026-00069", + "name": "Multimodal image-hidden instructions (SkillCamo) bundled within a skill package", + "shortDescription": { + "text": "Obfuscation - Multimodal Image-Hidden Instructions" + }, + "fullDescription": { + "text": "A skill package bundles an image resource whose visual content encodes instructions not present anywhere in the package's own text (documentation, manifest, or source), with surrounding documentation phrased to reference the image as an ordinary asset rather than describing what it actually contains." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00069", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 4.8, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00070", + "name": "Distributed cross-agent backdoor fragments reassembled externally after execution", + "shortDescription": { + "text": "Persistence - Distributed Cross-Agent Backdoor Fragments" + }, + "fullDescription": { + "text": "A tool's observation or return value delivered to an agent contains an encrypted or encoded fragment inconsistent with the tool's stated function, persisting in that agent's memory or context after the call, with no single agent's session containing enough fragments to reconstruct a complete instruction on its own." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00070", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 6.4, + "detection_stage": "runtime_drift_detected" + } + }, + { + "id": "AVE-2026-00071", + "name": "MCP daemon redirect via DOCKER_HOST or host flag, container operations land on attacker infrastructure", + "shortDescription": { + "text": "Supply Chain - Container Daemon Redirect" + }, + "fullDescription": { + "text": "A component's settings.json env block, an MCP server's own env, or a committed command site sets DOCKER_HOST, or supplies a -H/--host flag, pointing the container daemon connection at a remote tcp:// or ssh:// host rather than the local daemon." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00071", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 5.6, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00072", + "name": "MCP server bound to all network interfaces with no authentication step (NeighborJack)", + "shortDescription": { + "text": "Insecure Configuration - Network Bind Exposure" + }, + "fullDescription": { + "text": "An MCP server's declared args or env set its bind address to the wildcard 0.0.0.0 or [::] rather than a loopback address or an explicitly scoped, narrower interface, with no accompanying authentication requirement for incoming connections." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00072", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 5, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00073", + "name": "Telemetry or API endpoint redirect via static configuration value", + "shortDescription": { + "text": "Data Exfiltration - Static Endpoint Redirect" + }, + "fullDescription": { + "text": "A component's committed configuration sets a telemetry exporter endpoint, a model/provider base URL, an MCP server URL, an agent_card_url, or an equivalent traffic-destination value to a host other than the component's own declared or default provider, or to a host reachable only over cleartext http://, with no accompanying instruction text and no content injected into the model's context." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00073", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 4.1, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00074", + "name": "Reclaimable dead external anchor (GitHub owner, package, domain, or cloud subdomain) referenced by a skill", + "shortDescription": { + "text": "Supply Chain - Dead Anchor Reclamation (SkillJacking)" + }, + "fullDescription": { + "text": "A skill's committed content (documentation, manifest, or install instructions) references an external GitHub owner/repo, installable package name, bare domain, or cloud subdomain that currently returns a not-found, unregistered, or deleted-account state from the relevant authority (GitHub's own user API, a package registry, domain RDAP, or a cloud provider's app-slug check), meaning the anchor is presently re-registerable by any third party even though it was a legitimate, resolvable target when the skill was authored." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00074", + "properties": { + "status": "active", + "severity": "HIGH", + "aivss_score": 7.1, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00075", + "name": "Bytecode poisoning: compiled .pyc cache diverges from its own reviewed .py source", + "shortDescription": { + "text": "Supply Chain - Compiled Bytecode / Source Divergence (Bytecode Poisoning)" + }, + "fullDescription": { + "text": "A skill package contains a .pyc (or .pyo) file whose disassembled bytecode references dangerous primitives (os.system, subprocess, eval, exec, socket, urlopen, credential file paths such as .aws/credentials or .ssh/id_) that do not appear anywhere in its sibling .py source's own text, meaning the compiled artifact the interpreter will actually load and execute contains capability its reviewed source does not show." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00075", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 4.4, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00076", + "name": "Natural-language steering of an approval classifier subagent, distinct from AVE-2026-00021 and AVE-2026-00063", + "shortDescription": { + "text": "Prompt Injection - Approval Classifier Steering" + }, + "fullDescription": { + "text": "A committed configuration file (Cursor's permissions.json) declares allow_instructions or block_instructions entries containing free-form natural-language sentences aimed at biasing a separate classifier subagent's approve/deny decision for unattended shell, MCP, or Fetch tool calls, rather than a boolean flag or an instruction embedded in the primary agent's own task content." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00076", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 4.5, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00077", + "name": "Cross-origin tool and resource declaration within a single MCP server manifest", + "shortDescription": { + "text": "Trust Boundary - Cross-Origin Tool and Resource Declaration" + }, + "fullDescription": { + "text": "A single MCP server's manifest declares tool and/or resource URL fields (parameters, input/output schemas, descriptions, metadata, or resource URIs) that resolve to two or more unique root domains, or that mix http:// and https:// schemes across those declared endpoints, with no false identity claim present -- honest, structural domain diversity within one server's own declared tool/resource surface." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00077", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 4.8, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00078", + "name": "Consensus poisoning: orchestrator accepts a single sub-agent result as authoritative with no quorum verification", + "shortDescription": { + "text": "Trust Boundary - Unverified Multi-Agent Consensus" + }, + "fullDescription": { + "text": "An orchestrator agent commits to a sub-task result supplied by exactly one sub-agent -- among two or more that were dispatched in parallel for the same sub-task, or in a single-source delegation chain with no independent check -- and forwards or acts on that result as ground truth with no quorum vote, redundancy comparison, or independent corroboration step evaluated first." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00078", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 6.4, + "detection_stage": "runtime_observed" + } + }, + { + "id": "AVE-2026-00079", + "name": "Plan hijacking via false completion signal: forced early termination bypasses undeclared execution steps", + "shortDescription": { + "text": "Execution Hijack - Plan-to-Execution Binding Bypass" + }, + "fullDescription": { + "text": "An agent's output (from a planner, an executor, or a poisoned tool result reaching either) contains a self-reported task-completion or high-certainty claim -- language equivalent to 'already completed', 'no further action needed', or an explicit confidence score used to justify stopping -- and the orchestrator invokes its final-answer or termination step in response, with the actual number of executed steps in the trace falling short of the number the declared plan specified, and no verification step comparing the two." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00079", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 6.2, + "detection_stage": "runtime_drift_detected" + } + }, + { + "id": "AVE-2026-00080", + "name": "Silent agent substitution: unverified process at a routing slot treated as the legitimate agent during retry (Sybil)", + "shortDescription": { + "text": "Trust Boundary - Runtime Agent Identity Substitution" + }, + "fullDescription": { + "text": "A tool call or agent invocation fails and the orchestrator retries at the same routing position; the response that arrives after the retry is accepted and forwarded downstream with no cryptographic credential, session token, or attestation check confirming it originates from the same agent instance that occupied the position before the failure, and no such check exists anywhere in the retry path." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00080", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 6.8, + "detection_stage": "runtime_observed" + } + }, + { + "id": "AVE-2026-00081", + "name": "Lingering authority: a task-scoped capability outlives the episode that justified it", + "shortDescription": { + "text": "Persistence - Lingering Authority" + }, + "fullDescription": { + "text": "A capability, tool permission, or access grant issued for one task, subgoal, or episode is invoked again after that episode's own closure event (task completion, subgoal resolution, incident closure, approval-window expiry) has already occurred in the same session, with no intervening revocation, re-grant, or re-authorization event recorded between the closure and the reuse." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00081", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 6.1, + "detection_stage": "runtime_observed" + } + }, + { + "id": "AVE-2026-00082", + "name": "Local skill name collision: deterministic router shadowing across discovery roots", + "shortDescription": { + "text": "local_skill_name_collision" + }, + "fullDescription": { + "text": "Two skill files under different local discovery roots resolve to an identical effective name (declared or filename-derived), and the agent's router silently invokes whichever one resolution order picks, with no check that the two roots carry different trust levels and no signal surfaced when the collision occurs." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00082", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 4.4, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00083", + "name": "Silent guardrail comparison failure: a protection mechanism that executes but never evaluates its verdict", + "shortDescription": { + "text": "Trust Boundary - Silent Guardrail Comparison Failure" + }, + "fullDescription": { + "text": "A guardrail, judge, approval gate, or similar protection-mechanism check executes on every request and returns a value read downstream as 'permitted' or 'no violation', without its own comparison, branch, or aggregation logic having actually evaluated the real verdict against the specific input in front of it -- because an elif is scoped under the wrong enclosing conditional making a verdict branch unreachable, an equality comparison is made against an unconstrained or loosely-typed value so any phrasing other than the one literal it expects falls through to the permissive branch, two code paths reach the same decision point with opposite defaults for identical input, an error-handling path omits the field the downstream verdict logic reads, or a security verdict is aggregated with all()/any() over a collection a caller-controlled configuration path can leave empty. The check's own logging, code coverage, and test suite all show it running normally, because the deciding branch is reached and executes -- it just never receives, or never compares against, the value that would make it fail." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00083", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 6.3, + "detection_stage": "runtime_observed" + } + }, + { + "id": "AVE-2026-00084", + "name": "Lifecycle hook trust decoupling: a vetted plugin update silently rebinds hooks outside the model's decision path", + "shortDescription": { + "text": "Supply Chain - Lifecycle Hook Trust Decoupling" + }, + "fullDescription": { + "text": "A plugin or skill that already passed marketplace/registry vetting under a benign, reviewed lifecycle-hook configuration receives a later version update, published under the same stable public identity, that adds or changes the shell command bound to a lifecycle event (session start, tool invocation, file or config edit). The harness applies the updated hook binding via its own automatic update-sync path, with no new LLM decision, per-entry re-authorization, or user-facing notification distinguishing the updated binding from the plugin's original, already-reviewed state. When the bound event next fires, the harness dispatches the attacker-chosen command as a subprocess directly from its own event-dispatch layer, never passing through the model's own reasoning or tool-call decision, so the exploitation step is invisible to any defense that only inspects prompts, model outputs, or tool calls." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00084", + "properties": { + "status": "active", + "severity": "HIGH", + "aivss_score": 7, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00085", + "name": "Collusive cross-skill composition: a malicious workflow split across independently benign skills", + "shortDescription": { + "text": "Obfuscation - Collusive Cross-Skill Composition" + }, + "fullDescription": { + "text": "Three or more independently-installed skill files, each with a real, narrow, individually-benign function, connect through genuine runtime artifacts (a file, an environment variable, a task-state value) that one sub-skill's actual execution produces and a subsequent sub-skill's execution consumes. No single sub-skill's declared instructions, code, or permissions contain the harmful behavior; it exists only in the ordered composition's real data flow once all sub-skills are installed together and executed in their intended sequence during genuine agent operation, so a scanner that evaluates each skill's own content and behavior in isolation, without cross-skill dependency or artifact-flow analysis, finds nothing to flag in any individual skill." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00085", + "properties": { + "status": "active", + "severity": "HIGH", + "aivss_score": 7.1, + "detection_stage": "static_detection" + } + }, + { + "id": "AVE-2026-00086", + "name": "Mid-session WebMCP tool hijacking: a live registry swap replaces an already-discovered tool under its own name", + "shortDescription": { + "text": "Trust Boundary - Mid-Session Tool Registry Hijacking" + }, + "fullDescription": { + "text": "A tool an agent has already discovered, and in some cases already invoked, within a live WebMCP session is unregistered (via a browser lifecycle API such as AbortSignal, or by losing a registration-order race before it ever registers) and a malicious replacement is registered under the exact same tool name, by a third-party script executing on the same page rather than by the tool's own origin. The agent's subsequent invocation of that tool name is dispatched to the attacker's replacement implementation with no content, schema, or description change signaling the substitution, and no mechanism in the agent's own tool-selection logic checks whether the implementation currently bound to a trusted name is the same one that was present when the name was first trusted." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00086", + "properties": { + "status": "active", + "severity": "HIGH", + "aivss_score": 7, + "detection_stage": "runtime_observed" + } + }, + { + "id": "AVE-2026-00087", + "name": "Agentjacking: a crafted tool response visually mimics a trusted system template to hijack an agent", + "shortDescription": { + "text": "Prompt Injection - Tool Response Template Mimicry" + }, + "fullDescription": { + "text": "An MCP tool response, returned by a legitimate, correctly functioning integration server in answer to an agent's own genuine query (an error lookup, a diagnostic check), contains content an attacker injected upstream at the integration's own publicly-writable ingest point, formatted with markdown or equivalent structured styling that exactly mimics the integration's authentic, system-generated output template. The agent's own handling of the tool response treats it as authoritative system data rather than untrusted external content, finds no visual or structural cue distinguishing it from a genuine event because the formatting is indistinguishable from the real template, and executes an embedded command the injected content presents as legitimate remediation guidance." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00087", + "properties": { + "status": "active", + "severity": "HIGH", + "aivss_score": 7.8, + "detection_stage": "runtime_observed" + } + }, + { + "id": "AVE-2026-00088", + "name": "Sandbox side-effect trust handoff: an agent-written workspace file is run by a trusted component outside the sandbox", + "shortDescription": { + "text": "Sandbox Escape - Side-Effect Trust Handoff" + }, + "fullDescription": { + "text": "A sandboxed agent, steered by content it processes, writes a file inside the workspace it is permitted to write (a hook definition, an editor task, Git metadata or hooks, the agent tool's own project configuration, or an interpreter in a virtualenv), and a more-privileged component outside the sandbox later loads and executes that file as trusted configuration or code, without distinguishing agent-written files from user-authored ones and without applying the sandbox's execution policy, so the agent's side effect runs on the host." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00088", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 6.4, + "detection_stage": "runtime_observed" + } + }, + { + "id": "AVE-2026-00089", + "name": "Model-supplied sandbox boundary: a tool parameter the model sets defines or widens the sandbox's writable scope", + "shortDescription": { + "text": "Sandbox Escape - Model-Supplied Policy Boundary" + }, + "fullDescription": { + "text": "A coding agent's sandbox computes its writable scope from a value the model supplies in a tool call (a terminal command's working directory or an equivalent path parameter) instead of from the session's user-established root, so a model steered by content it reads sets that value to a location outside the workspace and the sandbox grants write access there, letting the agent overwrite files such as the sandbox's own helper or the user's shell startup files without approval." + }, + "helpUri": "https://aveproject.org/registry.html#AVE-2026-00089", + "properties": { + "status": "active", + "severity": "MEDIUM", + "aivss_score": 6.6, + "detection_stage": "runtime_observed" + } + } + ] +} diff --git a/docs/specs/ave-implementer-guide.md b/docs/specs/ave-implementer-guide.md index eb7a5eb..98237ac 100644 --- a/docs/specs/ave-implementer-guide.md +++ b/docs/specs/ave-implementer-guide.md @@ -213,9 +213,10 @@ why the SHA-256 goes in too. **SARIF.** Follow [AVE-in-SARIF](ave-in-sarif.md): `result.ruleId` is the `ave_id` (or, if your rules keep their own ids, `properties.ave_id` on each -result and on its rule: the spec accepts both), each AVE record that produced a -result has an entry in `tool.driver.rules`, and the catalog goes in the run's -property bag: +result and on its rule, or a `relationships` link from the rule to the AVE +taxonomy with `taxa` on the result: the spec accepts all three), each AVE record +that produced a result has an entry in `tool.driver.rules`, and the catalog goes +in the run's property bag: ```json { @@ -237,6 +238,18 @@ property bag: The spec has the full mapping, including the `rules` block, `taxonomies` and which fields never belong on a rule. +**The AVE taxonomy.** Do not write the taxonomy block by hand. `dist/ave-taxonomy-latest.json` is +the AVE taxonomy as a SARIF `toolComponent`, generated from the records with a frozen `guid`, and +`scripts/build_taxonomy.py` builds the subset a scanner embeds, so names and links match the catalog: + +```bash +python3 scripts/build_taxonomy.py --only AVE-2026-00001,AVE-2026-00075 --out - +``` + +Put that object in the run's `taxonomies`. `--records`, `--release`, `--release-date` and `--download-uri` +stamp it for a catalog release you pin. `python3 scripts/ave_conformance.py check` compares what you embed +with the catalog. + **Your own JSON.** The same fields, under whatever names fit your format: ```json @@ -267,7 +280,7 @@ python scripts/ave_conformance.py check output.sarif --catalog ave-records.json python scripts/ave_conformance.py check output.sarif --catalog ave-records.json --require-ids ``` -`extract` is tolerant: it prints the AVE ids found in the output as JSON, each with `via` (how it was found) and `where` (the artifact, or the JSON path for output that is not SARIF), so any tool's output can be scored whatever its format. It reads SARIF in either form (a result's `ruleId`, or `properties.ave_id` on the result or its rule) and any JSON object with an `ave_id`, `AVEID`, `AveId` or `ave-id` key, or an `ave_ids` list, at any depth. +`extract` is tolerant: it prints the AVE ids found in the output as JSON, each with `via` (how it was found) and `where` (the artifact, or the JSON path for output that is not SARIF), so any tool's output can be scored whatever its format. It reads SARIF in any of the three forms (a result's `ruleId`; `properties.ave_id` on the result or its rule; or the AVE references in the rule's `relationships` and the result's `taxa`) and any JSON object with an `ave_id`, `AVEID`, `AveId` or `ave-id` key, or an `ave_ids` list, at any depth. `check` is strict: it judges the output against [AVE-in-SARIF](ave-in-sarif.md) and the catalog file, and prints a JSON report to stdout (and a one-line verdict to stderr): @@ -288,6 +301,9 @@ The exit status is 0 for `pass` and for `warn`, 1 for `warn` with `--strict`, an | error | `result_ave_id_missing`, `rule_ave_id_missing` | form B without `properties.ave_id` on the result, or on the rule | | error | `id_mismatch` | a `ruleId` and a `properties.ave_id` that name different classes, or a result and its rule that do | | error | `taxonomy_version_mismatch` | an AVE taxonomy `version` that is not `ave_catalog` without its `v` (or a `version` when `ave_catalog` is `latest`) | +| error | `taxonomy_guid_mismatch` | an AVE taxonomy whose `guid` is not AVE's (`5110b285-34d7-5334-94db-0308b24cfb49`) | +| error | `reference_guid_mismatch` | a `relationships` or `result.taxa` reference naming the component `AVE` with another `guid`; it is a different taxonomy and is not counted | +| error | `taxon_unknown` | a taxon in the AVE taxonomy whose id is not in the catalog given | | error | `unknown_ave_id` | an id that is not in the catalog given | | error | `sarif_no_runs`, `not_json`, `input_unreadable`, `catalog_unreadable` | input the check cannot read | | warn (error with `--require-ids`) | `no_ave_id` | a result whose `ruleId` is not an AVE id and that carries no `properties.ave_id` | @@ -295,6 +311,9 @@ The exit status is 0 for `pass` and for `warn`, 1 for `warn` with `--strict`, an | warn | `run_property_missing` | none of `ave_catalog`, `ave_schema_version`, `ave_records_sha256` on a run | | warn | `catalog_sha_differs` | a run that says it used records other than the catalog file given | | warn | `taxonomies_missing`, `taxonomy_version_missing`, `taxon_missing` | no AVE taxonomy, one without a `version`, or no taxon for a class a result cites | +| warn | `taxonomy_guid_missing` | an AVE taxonomy without a `guid` | +| warn | `taxon_name_differs` | a taxon whose `name` is not the catalog's title for that class | +| warn | `supported_taxonomies_missing` | results related to AVE classes, but `tool.driver.supportedTaxonomies` does not declare AVE | | warn | `no_results`, `no_ave_ids`, `catalog_not_supplied` | nothing to judge (no results, or results of which none names an AVE class), or no catalog to judge it against | A result that names no AVE class is a warning, because a tool may report findings outside AVE in the same file (a cfgaudit rule with no AVE mapping, for example): the check judges the results that do name a class. `--require-ids` makes such a result an error, for a tool that means every result to be an AVE finding. A conforming output says nothing about whether the findings are right; it means a consumer can read which class each finding claims and which catalog the scan used. diff --git a/docs/specs/ave-in-sarif.md b/docs/specs/ave-in-sarif.md index 4216a44..98f8918 100644 --- a/docs/specs/ave-in-sarif.md +++ b/docs/specs/ave-in-sarif.md @@ -1,4 +1,4 @@ -# AVE-in-SARIF Convention v1.1 +# AVE-in-SARIF Convention v1.2 This document specifies how AVE findings travel as SARIF (Static Analysis Results Interchange Format, OASIS Standard v2.1.0) so they reach the GitHub Security tab and CI systems without any extra integration work. @@ -19,20 +19,43 @@ AVE records are static vulnerability definitions. A scanner (e.g. bawbel/scanner --- -## Two ways to carry the AVE id +## Three ways to carry the AVE id -A result names its AVE class in one of two forms. Both are conformant, and a consumer reads either. +A result names its AVE class in one of three forms. All three are conformant, and a consumer reads any of them. -| | Form A: the AVE id is the rule id | Form B: the tool keeps its own rule id | -|---|---|---| -| `result.ruleId` | the `ave_id`, e.g. `AVE-2026-00001` | the tool's own rule id, e.g. `example-rule-7` | -| `rules[].id` | the `ave_id` | the same tool rule id | -| `result.properties.ave_id` | not needed | the `ave_id` (required) | -| `rules[].properties.ave_id` | not needed | the `ave_id` (required) | +| | Form A: the AVE id is the rule id | Form B: the tool keeps its own rule id | Form C: the tool's rule is related to the AVE taxonomy | +|---|---|---|---| +| `result.ruleId` | the `ave_id`, e.g. `AVE-2026-00001` | the tool's own rule id, e.g. `example-rule-7` | the tool's own rule id | +| `rules[].id` | the `ave_id` | the same tool rule id | the same tool rule id | +| `result.properties.ave_id` | not needed | the `ave_id` (required) | not needed | +| `rules[].properties.ave_id` | not needed | the `ave_id` (required) | not needed | +| `rules[].relationships[]` | not needed | not needed | one reference to the class per AVE class the rule relates to (required) | +| `result.taxa[]` | not needed | not needed | the same reference, for each class the result falls into (SARIF 3.27.8) | +| `tool.driver.supportedTaxonomies[]` | not needed | not needed | `{"name": "AVE", "guid": "5110b285-34d7-5334-94db-0308b24cfb49"}` (recommended) | + +Form A suits a scanner whose rules are AVE classes. Form B suits a scanner whose rules are finer than AVE classes, or exist beyond AVE: several of its rules can name one class, and its own rule ids stay stable for its own users. Form C is SARIF's own way of relating a rule to a classification (3.49.15 and 3.53, with CWE as the specification's example), so a consumer that already understands `taxa` reads AVE classes without knowing anything about AVE's properties. It suits a scanner that wants the AVE taxonomy to travel as a taxonomy. In every form a result's `ruleId` matches a `rules[].id` in the same run, and everything else in this document applies unchanged. + +A reference in form C names the class by `id` and the taxonomy by `toolComponent`: + +```json +{ + "target": { + "id": "AVE-2026-00001", + "toolComponent": { "name": "AVE", "guid": "5110b285-34d7-5334-94db-0308b24cfb49" } + }, + "kinds": ["relevant"] +} +``` + +In `result.taxa` the same reference appears without `target` and `kinds`: `{ "id": "AVE-2026-00001", "toolComponent": { "name": "AVE", "guid": "5110b285-34d7-5334-94db-0308b24cfb49" } }`. -Form A suits a scanner whose rules are AVE classes. Form B suits a scanner whose rules are finer than AVE classes, or exist beyond AVE: several of its rules can name one class, and its own rule ids stay stable for its own users. In either form a result's `ruleId` matches a `rules[].id` in the same run, and everything else in this document applies unchanged. +**Which `kinds`.** SARIF 3.53.3 defines the relationship kinds, and defaults an absent `kinds` to `["relevant"]`. AVE recommends writing `["relevant"]`, for these reasons from the text of 3.53.3 and 3.27.8: -A consumer reading ids takes `result.ruleId` when it is an AVE id, and otherwise `result.properties.ave_id`. [`scripts/ave_conformance.py`](../../scripts/ave_conformance.py) does exactly this, and judges an output against both forms (see the [implementer guide](ave-implementer-guide.md#check-your-output)). +- `relevant` is the kind for a relationship "not covered by other relationship kinds", and a tool's rule rarely is the same set of findings as an AVE class (`equal`). The crosswalks in this repository claim class-level equivalence, not identity. +- `equal` and `superset` let a producer leave the reference out of `result.taxa`, because the result is then taken to fall into the taxon implicitly (3.27.8, 3.53.3 note 2). That makes the class a claim about the rule. AVE's findings are claims about one detection, as `confidence` is, so each result should list the classes it falls into, and `relevant` keeps it that way. +- Use `equal` only for a rule that detects exactly the class. `subset`, `superset` and `incomparable` say how much of a class a rule covers, which AVE's records do not define; a producer who can state it may use them, and the checker does not judge `kinds`. + +A consumer reading ids takes `result.ruleId` when it is an AVE id, otherwise `result.properties.ave_id` (then the rule's), otherwise the AVE references in the rule's `relationships` and the result's `taxa`. A reference counts as AVE when its `toolComponent` has AVE's `guid`; with no `guid` it counts by the name `AVE`; another `guid` is another taxonomy. [`scripts/ave_conformance.py`](../../scripts/ave_conformance.py) does exactly this, and judges an output against all three forms (see the [implementer guide](ave-implementer-guide.md#check-your-output)). --- @@ -40,12 +63,13 @@ A consumer reading ids takes `result.ruleId` when it is an AVE id, and otherwise ### rules block — static record data (one entry per AVE record) -Each AVE record that produced at least one detection must appear in `run.tool.driver.rules` (form B: the tool's rule that produced it, carrying the id in `properties.ave_id`): +Each AVE record that produced at least one detection must appear in `run.tool.driver.rules` (form B: the tool's rule that produced it, carrying the id in `properties.ave_id`; form C: the tool's rule, related to the class through `relationships`): | SARIF field | AVE source | Notes | |---|---|---| | `rules[].id` | `ave_id` | e.g. `"AVE-2026-00001"`; in form B the tool's own rule id | | `rules[].properties.ave_id` | `ave_id` | form B only: the AVE class this rule reports | +| `rules[].relationships[]` | `ave_id` | form C only: one reference per AVE class the rule relates to (`target.id` and `target.toolComponent`), with `kinds` | | `rules[].name` | `attack_class` | e.g. `"external_instruction_fetch"` | | `rules[].shortDescription.text` | `title` | human-readable title | | `rules[].fullDescription.text` | `description` | full paragraph description | @@ -65,6 +89,7 @@ Each detection instance is a SARIF `result`: |---|---|---| | `result.ruleId` | `ave_id` | form A; in form B the tool's own rule id. Either way it must match a `rules[].id` in the same run | | `result.properties.ave_id` | `ave_id` | form B only: required, and the same as the rule's | +| `result.taxa[]` | `ave_id` | form C only: a reference (`id` and `toolComponent`) for each AVE class the result falls into | | `result.message.text` | `behavioral_fingerprint` + match location | e.g. `"External URL fetch in tool description at line 12"` | | `result.level` | severity mapping (see below) | `"error"`, `"warning"`, or `"note"` | | `result.locations[].physicalLocation` | scanner-determined | file path + region (line/column) | @@ -116,11 +141,12 @@ SARIF `result.properties.confidence` carries the **per-detection confidence** ## SARIF taxonomies block -Include an AVE taxonomy entry alongside the `runs` array so that tools can cross-reference findings against the full AVE record set: +Include an AVE taxonomy entry in the run's `taxonomies` array (SARIF 3.19.3: standard taxonomies are stored in `run.taxonomies`, and without rules) so that tools can cross-reference findings against the AVE record set: ```json "taxonomies": [ { + "guid": "5110b285-34d7-5334-94db-0308b24cfb49", "name": "AVE", "version": "1.2.0", "releaseDateUtc": "2026-10-29", @@ -128,7 +154,7 @@ Include an AVE taxonomy entry alongside the `runs` array so that tools can cross "downloadUri": "https://github.com/aveproject/ave/releases/download/v1.2.0/ave-records.json", "organization": "AVE Project", "shortDescription": { - "text": "Agentic Vulnerability Enumeration — behavioral vulnerability classes for agentic AI components" + "text": "Agentic Vulnerability Enumeration: behavioral vulnerability classes for agentic AI components" }, "taxa": [ { @@ -145,6 +171,16 @@ Add one taxon per AVE record that appears in the scan results. Scanners may incl `version` is the catalog release the scan used, without its `v` (the same release as `runs[].properties.ave_catalog`), `releaseDateUtc` is that release's publication date, and `downloadUri` is that release's `ave-records.json`. A scanner tracking `dist/ave-records-latest.json` has no release to name: it omits `version` and `releaseDateUtc`, and uses `https://raw.githubusercontent.com/aveproject/ave/main/dist/ave-records-latest.json` as `downloadUri`. +**Identity.** The AVE taxonomy's `guid` is `5110b285-34d7-5334-94db-0308b24cfb49`, the UUIDv5 of `https://aveproject.org/taxonomy/AVE`, and it never changes. SARIF consumers match a taxonomy by `guid`, so a taxonomy with this guid is the AVE taxonomy whatever it is called, and one called `AVE` with another guid is not. Put the guid on the taxonomy and on every `toolComponent` reference to it: the checker warns when the taxonomy has none and reports an error when it has another. + +**The canonical file.** The taxonomy is generated, not written by hand. `dist/ave-taxonomy-latest.json` is a SARIF `toolComponent` with one taxon per AVE record, including records whose `status` is not `active` (the status is in the taxon's `properties`), built from `dist/ave-records-latest.json` by `python3 scripts/build_taxonomy.py` and kept in step with the records by the workflow that regenerates `dist/`. A scanner that cites a few classes embeds a subset, which says `isComprehensive: false`: + +```bash +python3 scripts/build_taxonomy.py --only AVE-2026-00001,AVE-2026-00075 --out - +``` + +The release-stamped form, for a scanner pinned to a catalog release, takes that release's records file and its facts: `python3 scripts/build_taxonomy.py --records ave-records.json --release v1.2.0 --release-date 2026-10-29 --download-uri --out -`. The file is not yet a catalog-release asset. A taxon's `id` and `name` are the record's `ave_id` and `title` exactly, and the checker compares them with the catalog (`taxon_unknown`, `taxon_name_differs`). + --- ## Example: minimal valid SARIF output @@ -187,6 +223,7 @@ One finding for AVE-2026-00001 (metamorphic payload via external config fetch) a }, "taxonomies": [ { + "guid": "5110b285-34d7-5334-94db-0308b24cfb49", "name": "AVE", "version": "1.2.0", "informationUri": "https://aveproject.org", @@ -270,6 +307,7 @@ The same finding from a scanner that keeps its own rule ids. Only the rule id an }, "taxonomies": [ { + "guid": "5110b285-34d7-5334-94db-0308b24cfb49", "name": "AVE", "version": "1.2.0", "informationUri": "https://aveproject.org", @@ -319,11 +357,112 @@ The same finding from a scanner that keeps its own rule ids. Only the rule id an --- +## Example: form C + +The same finding from a scanner that relates its own rule to the AVE taxonomy. Only the rule, the result's `taxa` and the `supportedTaxonomies` declaration differ from the examples above; the run properties and the taxonomy are the same. + +```json +{ + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "example-scanner", + "version": "1.0.0", + "rules": [ + { + "id": "example-rule-7", + "name": "Instructions fetched from a URL", + "relationships": [ + { + "target": { + "id": "AVE-2026-00001", + "toolComponent": { + "name": "AVE", + "guid": "5110b285-34d7-5334-94db-0308b24cfb49" + } + }, + "kinds": [ + "relevant" + ] + } + ] + } + ], + "supportedTaxonomies": [ + { + "name": "AVE", + "guid": "5110b285-34d7-5334-94db-0308b24cfb49" + } + ] + } + }, + "taxonomies": [ + { + "guid": "5110b285-34d7-5334-94db-0308b24cfb49", + "name": "AVE", + "version": "1.2.0", + "informationUri": "https://aveproject.org", + "taxa": [ + { + "id": "AVE-2026-00001", + "name": "Metamorphic payload via external config fetch" + } + ] + } + ], + "results": [ + { + "ruleId": "example-rule-7", + "level": "error", + "message": { + "text": "Component fetches its instructions from a URL at runtime, at line 14." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "skills/data-fetcher.md" + }, + "region": { + "startLine": 14 + } + } + } + ], + "taxa": [ + { + "id": "AVE-2026-00001", + "toolComponent": { + "name": "AVE", + "guid": "5110b285-34d7-5334-94db-0308b24cfb49" + } + } + ], + "properties": { + "confidence": 0.88, + "evidence_stage": "static_detection" + } + } + ], + "properties": { + "ave_catalog": "v1.2.0", + "ave_schema_version": "1.2.0", + "ave_records_sha256": "92e002e98cdd10f5de36e0ccfa80696b623cdadf302cc4d884f2a33b7fd94390" + } + } + ] +} +``` + +--- + ## Field placement summary | Data | Goes in `rules[]` | Goes in `result` | |---|---|---| -| `ave_id` | `rules[].id` (form B: `rules[].properties.ave_id`) | `result.ruleId` (form B: `result.properties.ave_id`) | +| `ave_id` | `rules[].id` (form B: `rules[].properties.ave_id`; form C: `rules[].relationships[].target.id`) | `result.ruleId` (form B: `result.properties.ave_id`; form C: `result.taxa[].id`) | | `title` | `rules[].shortDescription.text` | — | | `description` | `rules[].fullDescription.text` | — | | `behavioral_fingerprint` | — | `result.message.text` (with location) | @@ -357,7 +496,7 @@ For findings to appear correctly in the GitHub Security tab: ## Versioning -This convention has its own version, separate from the AVE schema's: **AVE-in-SARIF v1.1**. The two don't move in lockstep, because this document maps schema field *names* into SARIF, not a frozen schema snapshot. A record that validates against whatever the current AVE schema version is still maps the same way, as long as the field names and semantics this document references haven't changed. +This convention has its own version, separate from the AVE schema's: **AVE-in-SARIF v1.2**. The two don't move in lockstep, because this document maps schema field *names* into SARIF, not a frozen schema snapshot. A record that validates against whatever the current AVE schema version is still maps the same way, as long as the field names and semantics this document references haven't changed. Breaking changes to *this convention* (new required fields, removed fields, changed semantics) increment the major version and are announced with a 30-day notice period. Additive changes (new optional `result.properties.*` fields) are non-breaking and do not increment the version. A change that widens what a conforming output may contain, such as a second accepted form for the AVE id, is non-breaking for emitters but can need more of a consumer, so it increments the minor version. @@ -366,3 +505,5 @@ Breaking changes to *this convention* (new required fields, removed fields, chan **Revision note (2026-10-29):** added the recommended run properties `ave_catalog`, `ave_schema_version` and `ave_records_sha256`, which name the catalog release a scan used, now that releases are published with a manifest (`v1.2.0` onwards). Also stated what `taxonomies[].version`, `releaseDateUtc` and `downloadUri` hold, which this document had left unspecified: that same release's version, date and `ave-records.json`. Both examples moved from `1.1.0` to the `v1.2.0` release. The run properties are optional and no existing field was removed or changed, so the version stays v1.0. **Revision note (2026-10-31):** added form B, a second way to carry the AVE id (a tool's own `ruleId`, with `properties.ave_id` on the rule and on each result), because a tool that emits AVE ids in SARIF today does exactly that. Form A is unchanged. No field changed meaning and every output that was conformant still is, so this is a minor version, v1.1, not a major one; a consumer that read only `result.ruleId` must now also read `properties.ave_id` to see form B's ids. The same change adds `scripts/ave_conformance.py`, which checks an output against both forms. + +**Revision note (2026-10-31, v1.2):** added form C, a third way to carry the AVE id through SARIF's own taxonomy mechanism (a rule's `relationships` to the AVE taxonomy, the result's `taxa`, and `tool.driver.supportedTaxonomies`), and stated which `kinds` AVE recommends and why. The embedded AVE taxonomy gains a `guid` (`5110b285-34d7-5334-94db-0308b24cfb49`), a canonical generated file (`dist/ave-taxonomy-latest.json`, built by `scripts/build_taxonomy.py`, with a subset mode for scanners) and the rule that a taxonomy is identified by that guid. The checker gained form C extraction and six checks: `taxonomy_guid_missing`, `taxonomy_guid_mismatch`, `taxon_unknown`, `taxon_name_differs`, `reference_guid_mismatch` and `supported_taxonomies_missing`. Forms A and B are unchanged and every output that was conformant still is, with a `taxonomy_guid_missing` warning if it embeds an AVE taxonomy without a guid. A consumer that read only `result.ruleId` and `properties.ave_id` must now also read `rules[].relationships` and `result.taxa` to see form C's ids. A new form widens what a conforming output may contain, so this is a minor version. The spec's taxonomy example no longer has an em dash in its `shortDescription`; it matches the generated file. diff --git a/records/AVE-2026-00001.json b/records/AVE-2026-00001.json index 0c465f0..27378bd 100644 --- a/records/AVE-2026-00001.json +++ b/records/AVE-2026-00001.json @@ -56,6 +56,13 @@ "private_data" ] }, + "security_boundary": "reviewed artifact → executed artifact, with a mutable external fetch sitting unchecked between the two", + "missing_control": "no pinning or integrity check on runtime-fetched content that replaces a component's own behavior", + "vulnerability_rationale": { + "capability": "A skill or MCP component can fetch and execute remote content at runtime.", + "vulnerability": "No integrity binding exists between what was reviewed (the artifact and its declared behavior at scan time) and what actually executes (mutable, externally-fetched content at run time).", + "impact": "The fetched content replaces the component's original instructions, so an attacker can change its behavior after it has passed security review." + }, "mitigation": { "strategy": [ "pin_integrity", @@ -100,7 +107,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-01T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Greshake 2023", diff --git a/records/AVE-2026-00002.json b/records/AVE-2026-00002.json index d02f910..5ac6c5e 100644 --- a/records/AVE-2026-00002.json +++ b/records/AVE-2026-00002.json @@ -45,6 +45,13 @@ "untrusted_content" ] }, + "security_boundary": "tool metadata (should be descriptive, inert) → agent instruction (treated as authoritative context)", + "missing_control": "no structural separation between descriptive metadata and executable instruction within the tool manifest schema", + "vulnerability_rationale": { + "capability": "MCP tool description fields are read by the agent during tool discovery.", + "vulnerability": "No boundary separates \"metadata describing a tool\" from \"instructions the agent should follow\"; both share the same natural-language channel with nothing to distinguish them.", + "impact": "The agent treats the embedded instructions as authoritative context and follows attacker-controlled directives, before any tool is called." + }, "mitigation": { "strategy": [ "validate_input", @@ -89,7 +96,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-01T09:00:00Z", - "last_updated": "2026-08-29T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Greshake 2023", diff --git a/records/AVE-2026-00003.json b/records/AVE-2026-00003.json index 5c6ddae..efc6f37 100644 --- a/records/AVE-2026-00003.json +++ b/records/AVE-2026-00003.json @@ -47,6 +47,13 @@ "external_comms" ] }, + "security_boundary": "credential store → external destination", + "missing_control": "no content-aware egress control distinguishes legitimate outbound task data from credential exfiltration", + "vulnerability_rationale": { + "capability": "Agent can read env vars/credentials and make external network calls.", + "vulnerability": "No content-aware egress control distinguishes legitimate outbound task data from credential exfiltration.", + "impact": "Credential theft enabling follow-on compromise." + }, "mitigation": { "strategy": [ "least_privilege", @@ -91,7 +98,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-01T09:00:00Z", - "last_updated": "2026-08-23T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "CWE-522", diff --git a/records/AVE-2026-00006.json b/records/AVE-2026-00006.json index 037d99f..9759c5a 100644 --- a/records/AVE-2026-00006.json +++ b/records/AVE-2026-00006.json @@ -43,6 +43,13 @@ "external_comms" ] }, + "security_boundary": "tool-use decision → irreversible on-chain action", + "missing_control": "no structurally mandatory (vs. component-configurable) approval gate for irreversible financial actions specifically", + "vulnerability_rationale": { + "capability": "Agent with wallet tool access can transfer funds/approve allowances.", + "vulnerability": "No structurally mandatory human-approval gate exists for irreversible financial actions specifically.", + "impact": "Irreversible on-chain financial loss." + }, "mitigation": { "strategy": [ "require_human_approval", @@ -65,7 +72,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "MITRE ATT&CK T1657", diff --git a/records/AVE-2026-00007.json b/records/AVE-2026-00007.json index 70143f7..663e386 100644 --- a/records/AVE-2026-00007.json +++ b/records/AVE-2026-00007.json @@ -44,6 +44,13 @@ "untrusted_content" ] }, + "security_boundary": "trusted system instruction ↔ untrusted component content, same channel", + "missing_control": "no instruction-hierarchy enforcement distinguishes origin or recency", + "vulnerability_rationale": { + "capability": "Agent processes instruction-shaped text from untrusted components in the same channel as trusted system instructions.", + "vulnerability": "No instruction-hierarchy enforcement distinguishes trusted origin from untrusted, recently-seen text.", + "impact": "Complete behavioral takeover, enabling most other AVE attack classes as a follow-on payload." + }, "mitigation": { "strategy": [ "validate_input", @@ -66,7 +73,7 @@ "researcher": "Perez & Ribeiro", "researcher_url": "https://arxiv.org/abs/2211.09527", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Perez 2022", diff --git a/records/AVE-2026-00008.json b/records/AVE-2026-00008.json index 7de2ae2..2cfd8dd 100644 --- a/records/AVE-2026-00008.json +++ b/records/AVE-2026-00008.json @@ -45,6 +45,13 @@ "untrusted_content" ] }, + "security_boundary": "task-scoped tool access → durable, cross-session system modification", + "missing_control": "no restriction prevents task-scoped filesystem/shell access from writing to persistence locations (cron, startup scripts)", + "vulnerability_rationale": { + "capability": "Agent has legitimate filesystem/shell tool access for its task.", + "vulnerability": "No restriction prevents that task-scoped access from writing to system-persistence locations.", + "impact": "Durable compromise surviving reboot, reinstallation, or removal attempts." + }, "mitigation": { "strategy": [ "least_privilege", @@ -67,7 +74,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Cohen 2024", diff --git a/records/AVE-2026-00009.json b/records/AVE-2026-00009.json index a3bd1a4..f6ab53c 100644 --- a/records/AVE-2026-00009.json +++ b/records/AVE-2026-00009.json @@ -45,6 +45,13 @@ "untrusted_content" ] }, + "security_boundary": "agent's own configuration (trusted, set once) → content the agent processes (untrusted, arbitrary)", + "missing_control": "no enforced separation between \"instructions that configure the agent\" and \"content the agent merely reads\"", + "vulnerability_rationale": { + "capability": "Agent operates under safety/alignment constraints configured independently of the content it processes.", + "vulnerability": "No boundary prevents processed content from redefining the agent's own safety/alignment configuration; constraints that should be structurally immutable to in-context instruction are treated as negotiable.", + "impact": "The agent's built-in safety guidelines and ethical constraints are bypassed: it adopts an alternative identity that operates without restrictions." + }, "mitigation": { "strategy": [ "validate_input", @@ -67,7 +74,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-20T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Wei 2023", diff --git a/records/AVE-2026-00010.json b/records/AVE-2026-00010.json index ff32503..80768b6 100644 --- a/records/AVE-2026-00010.json +++ b/records/AVE-2026-00010.json @@ -45,6 +45,13 @@ "untrusted_content" ] }, + "security_boundary": "component-issued instruction → operator/user visibility of that instruction", + "missing_control": "no enforced transparency requirement independent of what the component itself permits the agent to disclose", + "vulnerability_rationale": { + "capability": "Agent can withhold information from its own output.", + "vulnerability": "No requirement that instructions reaching the agent be disclosed to the user or operator on request; there's no operator-visibility boundary the component's instructions can't also suppress.", + "impact": "A covert channel between the component and the agent: the component directs the agent's behavior without the user's awareness or consent." + }, "mitigation": { "strategy": [ "validate_input", @@ -67,7 +74,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-20T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Greshake 2023", diff --git a/records/AVE-2026-00011.json b/records/AVE-2026-00011.json index 3960a84..ec6a6c8 100644 --- a/records/AVE-2026-00011.json +++ b/records/AVE-2026-00011.json @@ -44,6 +44,13 @@ "untrusted_content" ] }, + "security_boundary": "task-descriptive content → direct tool-invocation command", + "missing_control": "no separation between content describing a task and content commanding a specific tool invocation with attacker-chosen parameters", + "vulnerability_rationale": { + "capability": "Agent selects and invokes tools based on task content.", + "vulnerability": "No boundary prevents component content from directly commanding tool invocations with attacker-chosen parameters, bypassing the agent's own selection logic.", + "impact": "Arbitrary tool invocation, including destructive, exfiltration, or lateral-movement capability the user never intended to activate." + }, "mitigation": { "strategy": [ "require_human_approval", @@ -66,7 +73,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-20T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Greshake 2023", diff --git a/records/AVE-2026-00012.json b/records/AVE-2026-00012.json index a9704cf..6bf7c11 100644 --- a/records/AVE-2026-00012.json +++ b/records/AVE-2026-00012.json @@ -44,6 +44,13 @@ "untrusted_content" ] }, + "security_boundary": "claimed permission (in-content) → actual authorization (never checked)", + "missing_control": "no verification checks an in-content permission claim against any real authorization system", + "vulnerability_rationale": { + "capability": "Agent can defer to permission claims made within its instruction context.", + "vulnerability": "No verification checks an in-content permission claim against any actual authorization system.", + "impact": "Agent performs actions it would otherwise refuse, believing itself newly authorized." + }, "mitigation": { "strategy": [ "verify_identity", @@ -66,7 +73,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-20T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "CWE-269", diff --git a/records/AVE-2026-00013.json b/records/AVE-2026-00013.json index 7467e4a..22bf7c6 100644 --- a/records/AVE-2026-00013.json +++ b/records/AVE-2026-00013.json @@ -45,6 +45,13 @@ "external_comms" ] }, + "security_boundary": "PII in agent context → external destination", + "missing_control": "no content-aware egress control distinguishes legitimate task output from PII exfiltration", + "vulnerability_rationale": { + "capability": "Agent can access and transmit user PII in the course of normal tasks.", + "vulnerability": "No content-aware egress control distinguishes legitimate task output from PII exfiltration.", + "impact": "Identity theft, financial fraud, and regulatory-violation exposure for affected users." + }, "mitigation": { "strategy": [ "least_privilege", @@ -67,7 +74,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-20T09:00:00Z", - "last_updated": "2026-08-23T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "CWE-359", diff --git a/records/AVE-2026-00014.json b/records/AVE-2026-00014.json index 87f081c..b482d82 100644 --- a/records/AVE-2026-00014.json +++ b/records/AVE-2026-00014.json @@ -37,6 +37,13 @@ "entry_class": "content", "payload_surface": "skill instruction body: false-authority framing" }, + "security_boundary": "claimed identity (asserted in content) → actual, verifiable identity (not checked against anything)", + "missing_control": "no authentication of in-band identity/authority claims", + "vulnerability_rationale": { + "capability": "Agent can act on authority claims present in content it processes.", + "vulnerability": "No mechanism authenticates in-content authority claims; any content can assert arbitrary authority with no verification step.", + "impact": "The agent follows instructions it would otherwise question, because it defers to the claimed authority within its trust hierarchy." + }, "mitigation": { "strategy": [ "verify_identity", @@ -59,7 +66,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-20T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "CWE-290", diff --git a/records/AVE-2026-00015.json b/records/AVE-2026-00015.json index b1edcbe..794afa9 100644 --- a/records/AVE-2026-00015.json +++ b/records/AVE-2026-00015.json @@ -40,6 +40,13 @@ "untrusted_content" ] }, + "security_boundary": "internal configuration → normal output channel", + "missing_control": "no confidentiality boundary prevents the agent's own operational configuration from being repeated back through its ordinary output", + "vulnerability_rationale": { + "capability": "Agent's output channel can include any content it has processed, including its own system prompt.", + "vulnerability": "No confidentiality boundary prevents internal configuration from being repeated back through the normal output channel on request.", + "impact": "Proprietary logic and security-policy disclosure, revealing attack surface for follow-on exploitation." + }, "mitigation": { "strategy": [ "validate_input", @@ -62,7 +69,7 @@ "researcher": "Perez & Ribeiro", "researcher_url": "https://arxiv.org/abs/2211.09527", "published": "2026-04-20T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Perez 2022", diff --git a/records/AVE-2026-00016.json b/records/AVE-2026-00016.json index 470fe32..f36601e 100644 --- a/records/AVE-2026-00016.json +++ b/records/AVE-2026-00016.json @@ -44,6 +44,13 @@ "private_data" ] }, + "security_boundary": "retrieved document (should be data) → trusted context (treated as instruction)", + "missing_control": "no boundary distinguishes RAG-retrieved content from instruction", + "vulnerability_rationale": { + "capability": "A RAG pipeline retrieves external document content into agent context at query time.", + "vulnerability": "No boundary distinguishes retrieved document content from instruction once it enters context.", + "impact": "Attacker-controlled instructions execute via a corpus the attacker needs no direct system access to." + }, "mitigation": { "strategy": [ "sanitize_output", @@ -87,7 +94,7 @@ "researcher": "Zou et al.", "researcher_url": "https://arxiv.org/abs/2402.07867", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-29T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Greshake 2023", diff --git a/records/AVE-2026-00017.json b/records/AVE-2026-00017.json index b4b242b..eb56a3c 100644 --- a/records/AVE-2026-00017.json +++ b/records/AVE-2026-00017.json @@ -43,6 +43,13 @@ "untrusted_content" ] }, + "security_boundary": "claimed server identity → actual, verified identity (never checked)", + "missing_control": "no identity verification mechanism for MCP servers; trust follows a self-asserted manifest claim", + "vulnerability_rationale": { + "capability": "Agent grants trust and permission scope based on a server's claimed identity.", + "vulnerability": "No verification checks a claimed server identity against anything real.", + "impact": "A malicious server receives elevated trust and permissions it has no legitimate claim to." + }, "mitigation": { "strategy": [ "verify_identity", @@ -86,7 +93,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "CWE-290", diff --git a/records/AVE-2026-00018.json b/records/AVE-2026-00018.json index 0eca3eb..1f49f4b 100644 --- a/records/AVE-2026-00018.json +++ b/records/AVE-2026-00018.json @@ -40,6 +40,13 @@ "untrusted_content" ] }, + "security_boundary": "actual tool execution result → reported result (agent sits unchecked in the path)", + "missing_control": "no integrity check verifies a reported tool result matches what the tool actually returned", + "vulnerability_rationale": { + "capability": "Agent reports tool call results to users and downstream components.", + "vulnerability": "No integrity check verifies a reported result matches what the tool actually returned.", + "impact": "False information, hidden errors, or manipulated downstream decisions based on fabricated data." + }, "mitigation": { "strategy": [ "validate_input", @@ -83,7 +90,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Greshake 2023", diff --git a/records/AVE-2026-00019.json b/records/AVE-2026-00019.json index 4ded35d..ba117cd 100644 --- a/records/AVE-2026-00019.json +++ b/records/AVE-2026-00019.json @@ -47,6 +47,13 @@ "private_data" ] }, + "security_boundary": "write request (untrusted) → persistent memory store (should be trusted)", + "missing_control": "no provenance or integrity check gates writes to persistent memory", + "vulnerability_rationale": { + "capability": "Agent maintains persistent memory across sessions.", + "vulnerability": "No provenance or integrity check gates writes to the persistent memory store.", + "impact": "Attacker-controlled beliefs influence agent behavior across all future sessions, long after the initial write." + }, "mitigation": { "strategy": [ "validate_input", @@ -90,7 +97,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Cohen 2024", diff --git a/records/AVE-2026-00020.json b/records/AVE-2026-00020.json index b55ed50..2ac6916 100644 --- a/records/AVE-2026-00020.json +++ b/records/AVE-2026-00020.json @@ -47,6 +47,13 @@ "untrusted_content" ] }, + "security_boundary": "orchestrator-intended output → sub-agent input, same channel", + "missing_control": "no boundary between task content and instruction at the agent-to-agent handoff specifically", + "vulnerability_rationale": { + "capability": "One agent's output becomes a downstream sub-agent's input in a delegation pipeline.", + "vulnerability": "No boundary distinguishes orchestrator-intended content from attacker-crafted instructions at the agent-to-agent handoff.", + "impact": "Downstream agent performs actions the orchestrator or user never intended, bypassing orchestrator-level safety controls." + }, "mitigation": { "strategy": [ "validate_input", @@ -90,7 +97,7 @@ "researcher": "Bawbel Security Research Team", "researcher_url": "https://bawbel.io", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-29T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Cohen 2024", diff --git a/records/AVE-2026-00021.json b/records/AVE-2026-00021.json index e99a6fb..892414b 100644 --- a/records/AVE-2026-00021.json +++ b/records/AVE-2026-00021.json @@ -41,6 +41,13 @@ "untrusted_content" ] }, + "security_boundary": "agent decision → irreversible/high-impact action", + "missing_control": "human confirmation is component-configurable behavior, not a structurally enforced gate", + "vulnerability_rationale": { + "capability": "Agent can take consequential or irreversible actions.", + "vulnerability": "Human confirmation for high-impact actions is component-configurable, not a structurally enforced gate.", + "impact": "Irreversible actions execute with no review opportunity, increasing the blast radius of any error or attack." + }, "mitigation": { "strategy": [ "require_human_approval", @@ -83,7 +90,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Greshake 2023", diff --git a/records/AVE-2026-00022.json b/records/AVE-2026-00022.json index 738ad36..1b04466 100644 --- a/records/AVE-2026-00022.json +++ b/records/AVE-2026-00022.json @@ -43,6 +43,13 @@ "untrusted_content" ] }, + "security_boundary": "reviewed artifact (declared manifest scope) → executed behavior (actual runtime access)", + "missing_control": "no scope enforcement at the agent-framework layer comparing runtime tool/resource calls against the component's own declared manifest", + "vulnerability_rationale": { + "capability": "Agent can invoke tools, APIs, files, or databases beyond what a skill's manifest declares as its required resource access.", + "vulnerability": "No runtime mechanism compares an agent's actual resource access against the manifest's declared scope. The manifest is a reviewed, trusted declaration; nothing enforces that declaration once the component runs.", + "impact": "The agent accesses resources beyond the component's declared scope, violating least privilege and possibly exposing sensitive data or systems that the user did not authorize." + }, "mitigation": { "strategy": [ "least_privilege", @@ -86,7 +93,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "CWE-269", diff --git a/records/AVE-2026-00023.json b/records/AVE-2026-00023.json index 82aba16..d985578 100644 --- a/records/AVE-2026-00023.json +++ b/records/AVE-2026-00023.json @@ -40,6 +40,13 @@ "untrusted_content" ] }, + "security_boundary": "constraint binding (should be persistent) → context-window position (where it actually, and non-persistently, lives)", + "missing_control": "no mechanism keeps safety constraints binding independent of how much content has since entered the context", + "vulnerability_rationale": { + "capability": "Agent's effective attention to system-prompt and safety content can vary with context volume.", + "vulnerability": "Safety and system constraints have no persistence guarantee independent of their position in the context window; they can be positionally evicted rather than remaining structurally binding.", + "impact": "Safety constraints, user instructions and conversation history are pushed out of the context window, so the model may become more susceptible to subsequent malicious instructions." + }, "mitigation": { "strategy": [ "validate_input", diff --git a/records/AVE-2026-00024.json b/records/AVE-2026-00024.json index 187058d..68edaba 100644 --- a/records/AVE-2026-00024.json +++ b/records/AVE-2026-00024.json @@ -41,6 +41,13 @@ "untrusted_content" ] }, + "security_boundary": "declared file extension → actual byte-level content", + "missing_control": "no content-type verification independent of the declared extension", + "vulnerability_rationale": { + "capability": "Skill files are loaded and trusted based on their declared extension.", + "vulnerability": "No content-type verification independent of the declared extension confirms the file's actual format before it's trusted.", + "impact": "Arbitrary executable content runs under the guise of a benign skill file, invisible to text-pattern scanners." + }, "mitigation": { "strategy": [ "validate_input", @@ -85,7 +92,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "CWE-434", diff --git a/records/AVE-2026-00025.json b/records/AVE-2026-00025.json index 895db0d..38658be 100644 --- a/records/AVE-2026-00025.json +++ b/records/AVE-2026-00025.json @@ -41,6 +41,13 @@ "untrusted_content" ] }, + "security_boundary": "genuine session history (should be structurally distinct) → arbitrary content shaped to resemble history (currently indistinguishable to the model)", + "missing_control": "no structural or cryptographic separation between real history and content merely formatted to look like it", + "vulnerability_rationale": { + "capability": "Agent relies on conversation history to infer prior user intent and consent.", + "vulnerability": "No integrity or provenance check distinguishes genuine prior-turn history from content merely styled to resemble it within the current turn's context.", + "impact": "The agent believes the user previously approved an action, said something they did not, or established a precedent that does not exist, which enables social engineering of its decisions." + }, "mitigation": { "strategy": [ "validate_input", @@ -84,7 +91,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Greshake 2023", diff --git a/records/AVE-2026-00026.json b/records/AVE-2026-00026.json index 09a0ea1..ecf1493 100644 --- a/records/AVE-2026-00026.json +++ b/records/AVE-2026-00026.json @@ -42,6 +42,13 @@ "external_comms" ] }, + "security_boundary": "tool-call parameters/return values → external transmission", + "missing_control": "monitoring inspects network destination, not tool-call payload content, for encoded sensitive data", + "vulnerability_rationale": { + "capability": "Agent can pass parameters to legitimate, already-authorized tools.", + "vulnerability": "No inspection of tool-call parameter or return content for encoded sensitive data.", + "impact": "Credential/PII/system-prompt exfiltration disguised as ordinary, legitimate-looking tool traffic." + }, "mitigation": { "strategy": [ "sanitize_output", diff --git a/records/AVE-2026-00027.json b/records/AVE-2026-00027.json index 48a3cd0..217da2f 100644 --- a/records/AVE-2026-00027.json +++ b/records/AVE-2026-00027.json @@ -45,6 +45,13 @@ "untrusted_content" ] }, + "security_boundary": "single-session, untrusted instruction → cross-session persistent behavior", + "missing_control": "no check on instructions that specifically target the agent's own persistence/memory behavior as their payload", + "vulnerability_rationale": { + "capability": "Agent's stated behavior can be shaped by instructions that ask it to \"remember\" something.", + "vulnerability": "No boundary prevents a single untrusted, single-session instruction from converting itself into cross-session persistent behavior via the agent's own compliance with a \"remember this\" directive.", + "impact": "A one-time injection becomes a persistent compromise: the instructions are re-applied in all future conversations, regardless of context resets, memory clears or new sessions." + }, "mitigation": { "strategy": [ "isolate_scope", @@ -89,7 +96,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Greshake 2023", diff --git a/records/AVE-2026-00028.json b/records/AVE-2026-00028.json index bcee92d..10f09fe 100644 --- a/records/AVE-2026-00028.json +++ b/records/AVE-2026-00028.json @@ -43,6 +43,13 @@ "untrusted_content" ] }, + "security_boundary": "uploaded document content (should be data) → instruction", + "missing_control": "no boundary distinguishes uploaded document content from instruction the agent should follow", + "vulnerability_rationale": { + "capability": "Agent processes user-uploaded documents as part of a task.", + "vulnerability": "No boundary distinguishes uploaded document content from instruction the agent should follow.", + "impact": "Indirect prompt injection requiring only that a user be convinced to upload a crafted document." + }, "mitigation": { "strategy": [ "validate_input", @@ -87,7 +94,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-29T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Greshake 2023", diff --git a/records/AVE-2026-00029.json b/records/AVE-2026-00029.json index 32ce1a9..39ddf48 100644 --- a/records/AVE-2026-00029.json +++ b/records/AVE-2026-00029.json @@ -40,6 +40,13 @@ "untrusted_content" ] }, + "security_boundary": "human visual review → model-level codepoint processing", + "missing_control": "no Unicode normalization/canonicalization check before human review", + "vulnerability_rationale": { + "capability": "Human reviewers evaluate text visually; the model processes Unicode codepoints.", + "vulnerability": "No canonicalization or normalization step reconciles what a human reviewer visually sees with what the model actually processes at the codepoint level.", + "impact": "Instructions that look innocuous to a human reviewer are processed as instructions by the model." + }, "mitigation": { "strategy": [ "validate_input", diff --git a/records/AVE-2026-00030.json b/records/AVE-2026-00030.json index a061aa3..b9adbf3 100644 --- a/records/AVE-2026-00030.json +++ b/records/AVE-2026-00030.json @@ -41,6 +41,13 @@ "untrusted_content" ] }, + "security_boundary": "claimed role → actually-verified role (never checked)", + "missing_control": "no authentication step backing role claims", + "vulnerability_rationale": { + "capability": "Skills can implement role-based access checks against user-supplied claims.", + "vulnerability": "Role-based access control is implemented by trusting a bare, self-asserted claim with no backing credential or authentication step.", + "impact": "Any user who simply claims the privileged role receives elevated access, bypassing all actual authentication." + }, "mitigation": { "strategy": [ "verify_identity", diff --git a/records/AVE-2026-00031.json b/records/AVE-2026-00031.json index e4ed0cd..597e995 100644 --- a/records/AVE-2026-00031.json +++ b/records/AVE-2026-00031.json @@ -44,6 +44,13 @@ "untrusted_content" ] }, + "security_boundary": "agent-generated output → training/RLHF feedback signal", + "missing_control": "no integrity check on agent-generated feedback prevents the evaluated system from also controlling its own evaluation signal", + "vulnerability_rationale": { + "capability": "Agent-generated outputs can feed into a downstream training/RLHF feedback pipeline.", + "vulnerability": "No integrity check prevents the evaluated system from also controlling its own evaluation signal.", + "impact": "Gradual, hard-to-detect manipulation of future model behavior via biased reward signals." + }, "mitigation": { "strategy": [ "validate_input", @@ -88,7 +95,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Wan 2023", diff --git a/records/AVE-2026-00032.json b/records/AVE-2026-00032.json index ae7493b..1c58933 100644 --- a/records/AVE-2026-00032.json +++ b/records/AVE-2026-00032.json @@ -43,6 +43,13 @@ "untrusted_content" ] }, + "security_boundary": "declared task scope → actual network reachability", + "missing_control": "no network segmentation or egress scoping tied to a skill's declared purpose; the agent's network capability is all-or-nothing rather than scoped per task", + "vulnerability_rationale": { + "capability": "Agent has network connectivity or shell access sufficient to reach internal hosts and services.", + "vulnerability": "No network-layer segmentation or scope check restricts an agent's granted network capability to the destinations its declared task actually requires.", + "impact": "The attacker gains intelligence for further attacks (network scans, enumerated services, a map of internal infrastructure), all executed from a trusted internal host." + }, "mitigation": { "strategy": [ "least_privilege", @@ -87,7 +94,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "CWE-918", diff --git a/records/AVE-2026-00034.json b/records/AVE-2026-00034.json index 105db06..1ad3b86 100644 --- a/records/AVE-2026-00034.json +++ b/records/AVE-2026-00034.json @@ -48,6 +48,13 @@ "external_comms" ] }, + "security_boundary": "external URL content → agent's full capability set", + "missing_control": "no identity/integrity verification gates dynamically-loaded code before execution", + "vulnerability_rationale": { + "capability": "Agent can dynamically load and execute code from a URL at runtime.", + "vulnerability": "No verification gates code loaded from an external URL before it executes with the agent's full capability set.", + "impact": "Full agent compromise via arbitrary attacker-controlled code with no static-review opportunity." + }, "mitigation": { "strategy": [ "pin_integrity", @@ -92,7 +99,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "CWE-829", diff --git a/records/AVE-2026-00036.json b/records/AVE-2026-00036.json index 5fc806a..476adf6 100644 --- a/records/AVE-2026-00036.json +++ b/records/AVE-2026-00036.json @@ -46,6 +46,13 @@ "untrusted_content" ] }, + "security_boundary": "task-scoped credentials/access → reach beyond original task scope", + "missing_control": "no boundary prevents reuse of granted access to reach systems beyond the declared task", + "vulnerability_rationale": { + "capability": "Agent has network connectivity and credentials/tokens scoped to its current task.", + "vulnerability": "No boundary prevents that access from being reused to reach systems beyond the original task's authorized scope.", + "impact": "Compromise expands from one pipeline segment to adjacent systems the attacker could not reach directly." + }, "mitigation": { "strategy": [ "least_privilege", @@ -90,7 +97,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "MITRE ATT&CK T1021", diff --git a/records/AVE-2026-00037.json b/records/AVE-2026-00037.json index d50c193..7f6c2a5 100644 --- a/records/AVE-2026-00037.json +++ b/records/AVE-2026-00037.json @@ -42,6 +42,13 @@ "untrusted_content" ] }, + "security_boundary": "text-channel untrusted-content boundary (exists) → image-channel untrusted-content boundary (does not exist)", + "missing_control": "no cross-modal equivalent of existing text-content trust boundaries", + "vulnerability_rationale": { + "capability": "Multimodal agents can read text embedded in images.", + "vulnerability": "Untrusted-content handling boundaries exist for text but have no equivalent for text rendered inside images; the same class of content is trusted or untrusted depending on which modality carries it.", + "impact": "A prompt injection vector that completely bypasses text-level security scanning, because the malicious instruction is never present as text in the input stream, only as pixels in an image." + }, "mitigation": { "strategy": [ "validate_input", @@ -86,7 +93,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-04-19T09:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Qi 2023", diff --git a/records/AVE-2026-00038.json b/records/AVE-2026-00038.json index 09b2a5c..1786ab4 100644 --- a/records/AVE-2026-00038.json +++ b/records/AVE-2026-00038.json @@ -44,6 +44,13 @@ "untrusted_content" ] }, + "security_boundary": "declared, bounded tool/delegation scope → actual, unbounded runtime use", + "missing_control": "no ceiling on tool invocations or sub-agent spawning, and no human checkpoint gating either, once a component's instructions grant \"unlimited\" authority", + "vulnerability_rationale": { + "capability": "Agent can use any declared tool and spawn sub-agents.", + "vulnerability": "No mechanism bounds how tool-use and sub-agent-spawning access is used once it is granted: there is no ceiling on invocations or spawning and no human checkpoint.", + "impact": "All scope boundaries and human oversight are removed, turning the agent into an unconstrained autonomous actor." + }, "mitigation": { "strategy": [ "least_privilege", diff --git a/records/AVE-2026-00039.json b/records/AVE-2026-00039.json index c57d89c..fa41879 100644 --- a/records/AVE-2026-00039.json +++ b/records/AVE-2026-00039.json @@ -44,6 +44,13 @@ "external_comms" ] }, + "security_boundary": "network-egress monitoring (exists) → content-level covert-channel monitoring (does not exist)", + "missing_control": "no content-level covert-channel detection independent of destination monitoring", + "vulnerability_rationale": { + "capability": "Agent output is reviewed by humans and monitored at the network layer.", + "vulnerability": "Exfiltration monitoring checks network destinations, not whether benign-looking output content itself encodes exfiltrated data; content-level exfiltration has no detection surface at all.", + "impact": "Sensitive data is exfiltrated through output that looks benign to a human reviewer, with no detection surface at the content level." + }, "mitigation": { "strategy": [ "sanitize_output", diff --git a/records/AVE-2026-00041.json b/records/AVE-2026-00041.json index f11303f..b65376b 100644 --- a/records/AVE-2026-00041.json +++ b/records/AVE-2026-00041.json @@ -48,6 +48,13 @@ "private_data" ] }, + "security_boundary": "discovery-layer metadata (read once, pre-execution) → agent context (treated as authoritative), with no execution-layer event for runtime monitoring to catch", + "missing_control": "no validation at server-card fetch time, and no detection surface at all for runtime/execution-layer monitoring, since nothing has executed yet", + "vulnerability_rationale": { + "capability": "An agent fetches and reads a server-card's tool descriptions before making any tool call.", + "vulnerability": "No boundary separates metadata describing a tool from instructions the agent should follow, here at the discovery layer: the server card is read before any tool call exists for runtime monitoring to observe.", + "impact": "Malicious instructions in tool descriptions, parameter descriptions or config schemas are loaded into the agent's context and executed immediately, before any user interaction and outside runtime monitoring's reach." + }, "mitigation": { "strategy": [ "validate_input", @@ -77,7 +84,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-05-01T00:00:00Z", - "last_updated": "2026-08-29T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Greshake 2023", diff --git a/records/AVE-2026-00042.json b/records/AVE-2026-00042.json index 27c1ab7..567c622 100644 --- a/records/AVE-2026-00042.json +++ b/records/AVE-2026-00042.json @@ -46,6 +46,13 @@ "external_comms" ] }, + "security_boundary": "tool result content (data) → code the agent generates and executes", + "missing_control": "no boundary prevents tool-result content from breaking out of data context into generated code", + "vulnerability_rationale": { + "capability": "Agent-generated orchestration code processes tool results in Code/REPL Mode.", + "vulnerability": "No boundary prevents tool result content from breaking out of data context into the code the agent generates and executes.", + "impact": "Arbitrary code execution bypassing all prompt-level, text-instruction filtering entirely." + }, "mitigation": { "strategy": [ "deny_by_default", @@ -76,7 +83,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-05-01T00:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "CWE-94", diff --git a/records/AVE-2026-00043.json b/records/AVE-2026-00043.json index 8fd4560..e823393 100644 --- a/records/AVE-2026-00043.json +++ b/records/AVE-2026-00043.json @@ -45,6 +45,13 @@ "untrusted_content" ] }, + "security_boundary": "rendered surface (what the user sees) → processed payload (what the model reads)", + "missing_control": "no consistency requirement between rendered and processed content from the same rich-UI payload", + "vulnerability_rationale": { + "capability": "MCP Apps can render rich UI elements the model also processes as context.", + "vulnerability": "No consistency check ensures what's rendered to the user matches what the model actually processes from the same payload.", + "impact": "Agent acts on instructions the user has no way to see, in an interface designed to look fully transparent." + }, "mitigation": { "strategy": [ "sanitize_output", @@ -74,7 +81,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-05-01T00:00:00Z", - "last_updated": "2026-08-29T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Greshake 2023", diff --git a/records/AVE-2026-00044.json b/records/AVE-2026-00044.json index 1525567..e0c049b 100644 --- a/records/AVE-2026-00044.json +++ b/records/AVE-2026-00044.json @@ -42,6 +42,13 @@ "untrusted_content" ] }, + "security_boundary": "task-result data (should be data) → trusted context from a \"completed\" task", + "missing_control": "no validation distinguishes result data from instruction, and the dispatch-to-consumption temporal gap bypasses synchronous safety checks", + "vulnerability_rationale": { + "capability": "Agent dispatches async tasks and later reads their results in a future turn.", + "vulnerability": "No validation distinguishes legitimate result data from instruction, and the temporal gap bypasses checks applied at dispatch time.", + "impact": "Injected content is treated as trusted context from a completed task rather than external, untrusted input." + }, "mitigation": { "strategy": [ "validate_input", @@ -72,7 +79,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-05-01T00:00:00Z", - "last_updated": "2026-09-27T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Greshake 2023", diff --git a/records/AVE-2026-00045.json b/records/AVE-2026-00045.json index 8e0d60d..368a251 100644 --- a/records/AVE-2026-00045.json +++ b/records/AVE-2026-00045.json @@ -47,6 +47,13 @@ "external_comms" ] }, + "security_boundary": "low-trust server's instruction → high-trust server's capability, same session", + "missing_control": "no per-server trust isolation within a single multi-server agent session", + "vulnerability_rationale": { + "capability": "A single agent session can connect to and act on multiple MCP servers simultaneously.", + "vulnerability": "No per-server trust isolation prevents a low-trust server's instruction from directing the agent's use of a co-connected high-trust server.", + "impact": "Confused-deputy escalation from low-privilege compromise to high-privilege action." + }, "mitigation": { "strategy": [ "isolate_scope", @@ -77,7 +84,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-05-01T00:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "CWE-269", diff --git a/records/AVE-2026-00046.json b/records/AVE-2026-00046.json index ca71d19..45d97f1 100644 --- a/records/AVE-2026-00046.json +++ b/records/AVE-2026-00046.json @@ -48,6 +48,13 @@ "private_data" ] }, + "security_boundary": "component's own declared tool scope → the shared tool-dispatch layer every component's calls route through, which one component can silently claim authority over", + "missing_control": "no isolation or authorization check preventing one component's hook registration from intercepting calls belonging to other components", + "vulnerability_rationale": { + "capability": "Components can register hooks/callbacks into the agent's tool dispatch layer.", + "vulnerability": "No authorization or integrity check on hook registration into a shared dispatch layer that all components' tool calls pass through.", + "impact": "A hook registered early silently intercepts or redirects all subsequent tool invocations, including those of other skills and system tools, to attacker-controlled callbacks, while the agent continues to believe it is calling the legitimate tool." + }, "mitigation": { "strategy": [ "deny_by_default", @@ -78,7 +85,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-05-16T00:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "CWE-601", diff --git a/records/AVE-2026-00048.json b/records/AVE-2026-00048.json index 38afe53..65889c1 100644 --- a/records/AVE-2026-00048.json +++ b/records/AVE-2026-00048.json @@ -44,6 +44,13 @@ "untrusted_content" ] }, + "security_boundary": "parent's full permission set → sub-agent, by default", + "missing_control": "no explicit trust-boundary or permission-scoping requirement on delegation", + "vulnerability_rationale": { + "capability": "Agent can delegate tasks to sub-agents or spawn child agents.", + "vulnerability": "No explicit trust boundary or permission-scoping requirement exists on delegation; sub-agents inherit full parent permissions by default.", + "impact": "Privilege laundering and audit evasion, since sub-agent actions may not appear in the parent's audit trail." + }, "mitigation": { "strategy": [ "least_privilege", @@ -74,7 +81,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-05-16T00:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "CWE-269", diff --git a/records/AVE-2026-00050.json b/records/AVE-2026-00050.json index 75e95d5..ae7f34f 100644 --- a/records/AVE-2026-00050.json +++ b/records/AVE-2026-00050.json @@ -3,7 +3,7 @@ "schema_version": "1.3.0", "status": "active", "published": "2026-06-21T00:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "component_type": "mcp_server", "title": "Parasitic Toolchain \u2014 Silent Tool Registration and Persistent Hook Injection", "attack_class": "Persistence - Parasitic Toolchain", @@ -53,6 +53,13 @@ "external_comms" ] }, + "security_boundary": "declared manifest scope → actual runtime tool-registry footprint", + "missing_control": "no conformance check between a component's registered footprint and its declared manifest", + "vulnerability_rationale": { + "capability": "Tools can register handlers into the agent's tool dispatch layer at runtime.", + "vulnerability": "No check verifies a component's actual registered footprint against its declared manifest, at registration or session restart.", + "impact": "A persistent, undeclared capability survives context resets, indistinguishable from a legitimately registered tool." + }, "mitigation": { "strategy": [ "deny_by_default", diff --git a/records/AVE-2026-00051.json b/records/AVE-2026-00051.json index af82e3b..729254c 100644 --- a/records/AVE-2026-00051.json +++ b/records/AVE-2026-00051.json @@ -3,7 +3,7 @@ "schema_version": "1.3.0", "status": "active", "published": "2026-06-21T00:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "component_type": "mcp_server", "title": "OAuth Discovery Rebinding \u2014 Authorization Endpoint Redirected to Attacker Server", "attack_class": "Supply Chain - OAuth Discovery Rebinding", @@ -48,6 +48,13 @@ "external_comms" ] }, + "security_boundary": "server's declared origin → discovery-document endpoint values (unverified)", + "missing_control": "no verification that discovery-document endpoints match the server's own declared origin", + "vulnerability_rationale": { + "capability": "Agent follows OAuth 2.0 Authorization Server Metadata / OIDC Discovery per the published standard.", + "vulnerability": "No verification that discovery-document endpoint values match the server's own declared origin before the agent trusts them.", + "impact": "Interception of authorization codes, access tokens, and credentials during the OAuth exchange." + }, "mitigation": { "strategy": [ "verify_identity", diff --git a/records/AVE-2026-00055.json b/records/AVE-2026-00055.json index d47439b..97adc1c 100644 --- a/records/AVE-2026-00055.json +++ b/records/AVE-2026-00055.json @@ -40,6 +40,13 @@ "private_data" ] }, + "security_boundary": "configuration data → process-spawn boundary", + "missing_control": "no validation gate between configuration/registry data and process execution", + "vulnerability_rationale": { + "capability": "An MCP client spawns a server as a subprocess using command/args from configuration data.", + "vulnerability": "No validation gate exists between untrusted configuration data and the process-spawn boundary.", + "impact": "Arbitrary OS command execution under the client's privileges before any protocol handshake occurs." + }, "mitigation": { "strategy": [ "deny_by_default", @@ -65,7 +72,7 @@ "researcher": "OX Security", "researcher_url": "https://www.ox.security", "published": "2026-07-10T00:00:00Z", - "last_updated": "2026-07-10T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "OX Security", diff --git a/records/AVE-2026-00056.json b/records/AVE-2026-00056.json index 141be2b..4369803 100644 --- a/records/AVE-2026-00056.json +++ b/records/AVE-2026-00056.json @@ -29,6 +29,13 @@ "external_comms" ] }, + "security_boundary": "agent-generated response content → client's automatic rendering (an unmonitored channel)", + "missing_control": "no inspection of response content for embedded exfiltration channels before client rendering acts on it", + "vulnerability_rationale": { + "capability": "Clients automatically render markdown/rich-content references in agent responses.", + "vulnerability": "No inspection of agent-generated response content for embedded exfiltration channels before automatic rendering fetches them.", + "impact": "Zero-interaction data exfiltration requiring no tool call and no obfuscation." + }, "mitigation": { "strategy": [ "sanitize_output", @@ -54,7 +61,7 @@ "researcher": "Aim Labs", "researcher_url": "https://arxiv.org/abs/2509.10540", "published": "2026-07-10T00:00:00Z", - "last_updated": "2026-08-09T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "CVE", diff --git a/records/AVE-2026-00057.json b/records/AVE-2026-00057.json index fdfbf6c..4584c70 100644 --- a/records/AVE-2026-00057.json +++ b/records/AVE-2026-00057.json @@ -3,7 +3,7 @@ "schema_version": "1.3.0", "status": "active", "published": "2026-07-14T00:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "component_type": "skill", "title": "Obfuscated or encoded skill payload designed to evade static scanners", "attack_class": "Obfuscation - Static Analysis Evasion", @@ -35,6 +35,13 @@ "trifecta_profile": { "requires": ["untrusted_content"] }, + "security_boundary": "as-scanned representation → as-executed representation", + "missing_control": "no decode-then-rescan step in the static-analysis pipeline", + "vulnerability_rationale": { + "capability": "Static scanners pattern-match against a skill's literal, as-written content.", + "vulnerability": "Static analysis operates on the encoded representation while execution operates on the decoded representation, with no decode-then-rescan step bridging the two.", + "impact": "Pattern-based and keyword-based static scanners fail to match the encoded form, while the decoded or executed form at runtime is fully malicious." + }, "mitigation": { "strategy": ["validate_input", "deny_by_default"], "enforcement_point": "static_scan", diff --git a/records/AVE-2026-00058.json b/records/AVE-2026-00058.json index 228aaa4..afdffa5 100644 --- a/records/AVE-2026-00058.json +++ b/records/AVE-2026-00058.json @@ -3,7 +3,7 @@ "schema_version": "1.3.0", "status": "active", "published": "2026-07-14T00:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "component_type": "skill", "title": "Deceptive skill trigger or activation-scope manipulation via misleading manifest description", "attack_class": "Social Engineering - Trigger Scope Deception", @@ -35,6 +35,13 @@ "trifecta_profile": { "requires": ["untrusted_content"] }, + "security_boundary": "declared manifest trigger/description → actual implemented behavior", + "missing_control": "no verification that declared triggers match real behavior before invocation decisions are made", + "vulnerability_rationale": { + "capability": "A skill's declared manifest trigger/description determines when it gets invoked.", + "vulnerability": "No verification checks that a declared trigger matches the skill's actual implemented behavior before invocation.", + "impact": "Over-broad or implicit invocation in contexts the skill's real behavior does not warrant." + }, "mitigation": { "strategy": ["validate_input", "provenance_label"], "enforcement_point": "server_card_fetch", diff --git a/records/AVE-2026-00059.json b/records/AVE-2026-00059.json index 694946b..8d6ff68 100644 --- a/records/AVE-2026-00059.json +++ b/records/AVE-2026-00059.json @@ -38,6 +38,13 @@ "requires": ["untrusted_content"], "amplifies": ["external_comms", "private_data"] }, + "security_boundary": "per-description review (isolated) → multi-description composition (never reviewed as a whole)", + "missing_control": "no cross-description, holistic review step exists", + "vulnerability_rationale": { + "capability": "MCP tool descriptions across multiple tools/servers are individually reviewed for malicious content.", + "vulnerability": "No cross-description review step exists; review is structurally confined to one description at a time.", + "impact": "A complete malicious instruction assembles at inference time with no single reviewable artifact ever having existed." + }, "mitigation": { "strategy": ["validate_input", "pin_integrity"], "enforcement_point": "server_card_fetch", @@ -62,7 +69,7 @@ "researcher": "Liu et al.", "researcher_url": "https://arxiv.org/abs/2606.27027", "published": "2026-07-15T00:00:00Z", - "last_updated": "2026-08-26T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "ShareLock research", diff --git a/records/AVE-2026-00063.json b/records/AVE-2026-00063.json index 99b4724..f6377e3 100644 --- a/records/AVE-2026-00063.json +++ b/records/AVE-2026-00063.json @@ -30,6 +30,13 @@ "requires": ["untrusted_content"], "amplifies": ["external_comms", "private_data"] }, + "security_boundary": "instruction-level review (exists) → configuration-level review (does not exist)", + "missing_control": "no requirement that safety-relevant config flags receive the same review rigor as instruction text", + "vulnerability_rationale": { + "capability": "Components can declare configuration flags controlling whether human approval is required.", + "vulnerability": "No requirement that safety-relevant configuration flags receive the same review scrutiny as instruction text.", + "impact": "A required human-in-the-loop control is silently removed with no instruction-level signal a reviewer would catch." + }, "mitigation": { "strategy": ["deny_by_default", "validate_input"], "enforcement_point": "server_card_fetch", @@ -49,7 +56,7 @@ "kill_switch_active": false, "researcher": "hackerone.com/cantina_xyz", "published": "2026-07-27T00:00:00Z", - "last_updated": "2026-10-20T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "CVE-2026-33068 (GHSA-mmgp-wc2j-qcv7)", diff --git a/records/AVE-2026-00064.json b/records/AVE-2026-00064.json index e133346..3054bea 100644 --- a/records/AVE-2026-00064.json +++ b/records/AVE-2026-00064.json @@ -29,6 +29,13 @@ "trifecta_profile": { "requires": ["untrusted_content"] }, + "security_boundary": "passive action (opening a project) → code execution, no confirmation", + "missing_control": "no confirmation gate on auto-run behavior triggered passively rather than by explicit tool call", + "vulnerability_rationale": { + "capability": "IDE/dev-environment configuration can declare commands to run automatically on project load.", + "vulnerability": "No confirmation gate exists for auto-run behavior triggered by a passive action rather than an explicit tool call.", + "impact": "Code execution requiring no action beyond opening a compromised project directory." + }, "mitigation": { "strategy": ["deny_by_default", "validate_input"], "enforcement_point": "server_card_fetch", @@ -49,7 +56,7 @@ "researcher": "Check Point Research (Aviv Donenfeld, Oded Vanunu)", "researcher_url": "https://research.checkpoint.com/2026/rce-and-api-token-exfiltration-through-claude-code-project-files-cve-2025-59536/", "published": "2026-07-27T00:00:00Z", - "last_updated": "2026-10-20T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Anthropic GHSA-ph6w-f82w-28w6", diff --git a/records/AVE-2026-00065.json b/records/AVE-2026-00065.json index d2f11d6..15c45fb 100644 --- a/records/AVE-2026-00065.json +++ b/records/AVE-2026-00065.json @@ -33,6 +33,13 @@ "requires": ["untrusted_content"], "amplifies": ["external_comms", "private_data"] }, + "security_boundary": "descriptive capability/identity metadata → instruction, once loaded into reasoning context", + "missing_control": "no boundary separates the A2A card's descriptive metadata from executable instruction once it is loaded into the host's reasoning context", + "vulnerability_rationale": { + "capability": "A host agent reads a remote agent's A2A card to plan task delegation.", + "vulnerability": "No boundary separates the card's descriptive metadata from executable instruction once loaded into the host's reasoning context.", + "impact": "Delegation planning hijacked by a malicious remote agent's self-declared, unverified metadata." + }, "mitigation": { "strategy": ["validate_input", "provenance_label"], "enforcement_point": "server_card_fetch", @@ -54,7 +61,7 @@ "researcher": "Kumar Aditya", "researcher_url": "https://www.keysight.com/blogs/en/tech/nwvs/2026/03/12/agent-card-poisoning", "published": "2026-07-27T00:00:00Z", - "last_updated": "2026-08-29T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Keysight research", diff --git a/records/AVE-2026-00066.json b/records/AVE-2026-00066.json index 7fd2db7..df9ae2d 100644 --- a/records/AVE-2026-00066.json +++ b/records/AVE-2026-00066.json @@ -32,6 +32,13 @@ "trifecta_profile": { "requires": ["external_comms"] }, + "security_boundary": "model's own hallucinated belief → fetch/install action", + "missing_control": "no registry-existence or publisher-identity check before acting on a model-generated resource name", + "vulnerability_rationale": { + "capability": "Agent resolves user requests for well-known resources to package/repo/skill names it generates itself.", + "vulnerability": "No registry-existence or publisher-identity check occurs before fetching or installing a model-generated name.", + "impact": "Malware installation via a scalable, precomputed, cross-model squatting technique with no injection required at all." + }, "mitigation": { "strategy": ["verify_identity", "pin_integrity"], "enforcement_point": "runtime_proxy", @@ -53,7 +60,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-08-02T00:00:00Z", - "last_updated": "2026-08-02T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Beware of Agentic Botnets (arXiv 2607.07433)", diff --git a/records/AVE-2026-00067.json b/records/AVE-2026-00067.json index 6d99e1c..37c54ca 100644 --- a/records/AVE-2026-00067.json +++ b/records/AVE-2026-00067.json @@ -23,6 +23,13 @@ "entry_class": "tool_response", "payload_surface": "a benign, correct upstream skill's output (endorsement, audit finding, validation result) consumed by a downstream skill as an implicit trust or authorization signal" }, + "security_boundary": "upstream skill's output (benign) → downstream skill's trust signal (unverified)", + "missing_control": "no requirement that a downstream skill independently re-verify a trust claim carried in an upstream skill's output", + "vulnerability_rationale": { + "capability": "A downstream skill can consume another skill's output as part of its own decision logic.", + "vulnerability": "No requirement exists for a downstream skill to independently re-verify a trust or authorization claim in an upstream skill's output.", + "impact": "Harmful actions approved based on a spoofable trust credential no single skill's isolated review would ever catch." + }, "mitigation": { "strategy": ["verify_identity", "isolate_scope"], "enforcement_point": "agent_framework", @@ -44,7 +51,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-08-02T00:00:00Z", - "last_updated": "2026-08-02T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Benign in Isolation, Harmful in Composition (arXiv 2606.15242)", diff --git a/records/AVE-2026-00068.json b/records/AVE-2026-00068.json index 2b4b3b5..74360fc 100644 --- a/records/AVE-2026-00068.json +++ b/records/AVE-2026-00068.json @@ -24,6 +24,13 @@ "payload_surface": "shared OS/shell state (environment variables, file descriptors, working directory, temp files) connecting sequential CLI command executions within one agent session", "escalation": "instruction_to_capability" }, + "security_boundary": "single-command security review → multi-command behavioral effect; the boundary is the unit of analysis itself, per-command versus per-sequence", + "missing_control": "no cross-command state-flow analysis; every existing tool's unit of analysis stops at the single command", + "vulnerability_rationale": { + "capability": "Agent can issue sequences of CLI commands, none individually dangerous.", + "vulnerability": "No producer-consumer tracking across a command sequence within one session; every existing control (ShellCheck, GTFOBins, LOLBAS, single-command scanners) evaluates each command in isolation, so the composition itself is structurally invisible to them.", + "impact": "Benign-looking commands compose through shared operating-system state into a capability beyond what the user's task authorized, which no single-command check observes; published research reports a 96.59% attack success rate across 2,525 trials." + }, "mitigation": { "strategy": ["isolate_scope", "least_privilege"], "enforcement_point": "runtime_proxy", @@ -45,7 +52,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-08-02T00:00:00Z", - "last_updated": "2026-08-02T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "MOSAIC (arXiv 2607.02857)", diff --git a/records/AVE-2026-00069.json b/records/AVE-2026-00069.json index b5cbaf3..7699370 100644 --- a/records/AVE-2026-00069.json +++ b/records/AVE-2026-00069.json @@ -24,6 +24,13 @@ "payload_surface": "an image resource bundled within the skill package, distinct from the package's documentation, manifest, or source code text", "escalation": "data_to_instruction" }, + "security_boundary": "text-only review pipeline → bundled image resource (never decoded for review)", + "missing_control": "no visual/multimodal decoding step exists in static review", + "vulnerability_rationale": { + "capability": "Multimodal agents can decode and act on bundled image content within a skill package.", + "vulnerability": "No visual/multimodal decoding step exists in the text-only static-review pipeline covering the rest of the package.", + "impact": "Instructions invisible to every current text-based scanner execute once a multimodal agent processes the resource." + }, "mitigation": { "strategy": ["validate_input", "sanitize_output"], "enforcement_point": "static_scan", @@ -45,7 +52,7 @@ "researcher": "Saray Chak", "researcher_url": "https://bawbel.io", "published": "2026-08-02T00:00:00Z", - "last_updated": "2026-08-02T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "SkillCamo (arXiv 2606.18198)", diff --git a/records/AVE-2026-00070.json b/records/AVE-2026-00070.json index 8d76c28..a8f4d14 100644 --- a/records/AVE-2026-00070.json +++ b/records/AVE-2026-00070.json @@ -28,6 +28,13 @@ "requires": ["untrusted_content"], "amplifies": ["private_data", "external_comms"] }, + "security_boundary": "dormant, per-agent fragments → externally reassembled, post-hoc payload", + "missing_control": "no anomaly detection for encoded fragments inconsistent with a tool's stated function, and no cross-agent correlation of dormant fragments", + "vulnerability_rationale": { + "capability": "Tools deliver observations to agents that persist in memory/context after the call.", + "vulnerability": "No anomaly detection or cross-agent correlation catches a fragmented payload no single session could ever contain enough of to detect.", + "impact": "A complete backdoor exists and becomes executable only after the fact, entirely outside any single session's visibility." + }, "mitigation": { "strategy": ["provenance_label", "isolate_scope"], "enforcement_point": "runtime_proxy", @@ -49,7 +56,7 @@ "researcher": "Pengyu Zhu, Lijun Li, Yaxing Lyu, Li Sun, Sen Su, Jing Shao", "researcher_url": "https://arxiv.org/abs/2510.11246", "published": "2026-08-02T00:00:00Z", - "last_updated": "2026-08-23T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Collaborative Shadows (arXiv 2510.11246)", diff --git a/records/AVE-2026-00071.json b/records/AVE-2026-00071.json index 79acca3..866ee72 100644 --- a/records/AVE-2026-00071.json +++ b/records/AVE-2026-00071.json @@ -33,6 +33,13 @@ "trifecta_profile": { "requires": ["external_comms"] }, + "security_boundary": "expected local daemon → actual, redirected remote daemon (unverified)", + "missing_control": "no verification that a declared daemon target matches the expected local daemon before build/run/pull proceeds", + "vulnerability_rationale": { + "capability": "Components can declare a container daemon connection target via configuration.", + "vulnerability": "No verification confirms a declared daemon target is the expected local daemon before operations proceed against it.", + "impact": "Secrets and bind-mounted data are exposed to whatever infrastructure actually receives the redirected connection." + }, "mitigation": { "strategy": ["deny_by_default", "pin_integrity"], "enforcement_point": "static_scan", @@ -54,7 +61,7 @@ "researcher": "Nicolai (predictor2718)", "researcher_url": "https://github.com/predictor2718", "published": "2026-08-06T00:00:00Z", - "last_updated": "2026-08-06T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "cfgaudit crosswalk gap detail", diff --git a/records/AVE-2026-00074.json b/records/AVE-2026-00074.json index befa798..d803e38 100644 --- a/records/AVE-2026-00074.json +++ b/records/AVE-2026-00074.json @@ -36,6 +36,13 @@ "trifecta_profile": { "requires": ["external_comms"] }, + "security_boundary": "trust established at authoring/review time → trust required at every subsequent execution, with no mechanism re-checking the gap between them", + "missing_control": "no ongoing verification that an already-approved external anchor is still controlled by its original owner", + "vulnerability_rationale": { + "capability": "Skills reference external identities (GitHub owners, package names, domains) that were valid at authoring time.", + "vulnerability": "No periodic re-verification that a previously-valid external identity reference remains currently owned by the same party; trust is established once, at review time, and never rechecked against real-world ownership changes.", + "impact": "An attacker who registers the now-unclaimed name takes control of everything the skill points at, without a single byte of the skill's own committed content changing." + }, "mitigation": { "strategy": ["verify_identity", "pin_integrity"], "enforcement_point": "static_scan", @@ -61,7 +68,7 @@ "researcher": "AIR Security", "researcher_url": "https://www.air.security", "published": "2026-08-07T00:00:00Z", - "last_updated": "2026-10-13T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "repo-forensics dead-anchor scanner", diff --git a/records/AVE-2026-00076.json b/records/AVE-2026-00076.json index 5343d98..bfbaa13 100644 --- a/records/AVE-2026-00076.json +++ b/records/AVE-2026-00076.json @@ -33,6 +33,13 @@ "trifecta_profile": { "requires": ["untrusted_content"] }, + "security_boundary": "steering text (targets the checker) → classifier's approve/deny judgment", + "missing_control": "no boundary prevents the same class of natural-language content that steers a primary agent from also steering the classifier meant to check it", + "vulnerability_rationale": { + "capability": "A committed configuration file can declare natural-language steering text consumed by a safety-classifier subagent.", + "vulnerability": "No boundary prevents natural-language content from probabilistically steering the classifier meant to check an agent's actions, the same way it steers the agent itself.", + "impact": "Auto-approval of shell/MCP/Fetch calls the classifier would otherwise flag, via a committed repository file." + }, "mitigation": { "strategy": ["require_human_approval", "deny_by_default"], "enforcement_point": "agent_framework", @@ -56,7 +63,7 @@ "researcher": "Nicolai (predictor2718)", "researcher_url": "https://github.com/predictor2718", "published": "2026-08-08T00:00:00Z", - "last_updated": "2026-08-08T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "predictor2718 PR #123", diff --git a/records/AVE-2026-00077.json b/records/AVE-2026-00077.json index 48769d6..f659e58 100644 --- a/records/AVE-2026-00077.json +++ b/records/AVE-2026-00077.json @@ -33,6 +33,13 @@ "trifecta_profile": { "requires": ["external_comms"] }, + "security_boundary": "single server's trust boundary → multiple, unrelated actual origins within it", + "missing_control": "no per-origin trust segmentation within one server's own declared manifest", + "vulnerability_rationale": { + "capability": "A single MCP server's manifest can declare tools/resources whose URLs span multiple distinct domains.", + "vulnerability": "No per-origin trust segmentation exists within one server's declared surface.", + "impact": "A minority-domain tool or resource can hijack context intended for the trusted majority origin, with no deception required." + }, "mitigation": { "strategy": ["isolate_scope", "deny_by_default"], "enforcement_point": "static_scan", @@ -56,7 +63,7 @@ "researcher": "Akash Krishna (akashjavelin)", "researcher_url": "https://github.com/akashjavelin", "published": "2026-08-10T00:00:00Z", - "last_updated": "2026-08-10T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "Ramparts cross-origin scanner", diff --git a/records/AVE-2026-00078.json b/records/AVE-2026-00078.json index 3f1bf19..3f8e4e6 100644 --- a/records/AVE-2026-00078.json +++ b/records/AVE-2026-00078.json @@ -30,6 +30,13 @@ "trifecta_profile": { "requires": ["untrusted_content"] }, + "security_boundary": "sub-agent result (unverified) → orchestrator's accepted ground truth (propagated downstream as though verified)", + "missing_control": "no quorum vote, redundancy comparison, or independent corroboration before committing to a single source's claim", + "vulnerability_rationale": { + "capability": "An orchestrator can dispatch sub-tasks to parallel sub-agents or accept results from a delegation chain.", + "vulnerability": "No quorum or redundancy check exists at the result-aggregation step of a multi-agent pipeline; a single compromised or adversarially-influenced source unilaterally determines the accepted output.", + "impact": "A single compromised or adversarially-influenced sub-agent unilaterally determines the pipeline's accepted output, which propagates downstream as though it had been verified." + }, "mitigation": { "strategy": ["validate_input", "deny_by_default"], "enforcement_point": "agent_framework", @@ -53,7 +60,7 @@ "researcher": "Faisal Haque Bappy, Tahrim Hossain, Tarannum Shaila Zaman, Raiful Hasan, Kamrul Hasan, Tariqul Islam", "researcher_url": "https://arxiv.org/abs/2608.00718", "published": "2026-08-14T00:00:00Z", - "last_updated": "2026-08-14T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "arXiv:2608.00718", diff --git a/records/AVE-2026-00079.json b/records/AVE-2026-00079.json index 66f685d..c895652 100644 --- a/records/AVE-2026-00079.json +++ b/records/AVE-2026-00079.json @@ -30,6 +30,13 @@ "trifecta_profile": { "requires": ["untrusted_content"] }, + "security_boundary": "declared plan (N steps) → actual executed trace (fewer steps, unverified)", + "missing_control": "no plan-to-execution-trace verification gates a self-reported completion signal", + "vulnerability_rationale": { + "capability": "An orchestrator tracks a declared plan and invokes a final step based on agent-reported status.", + "vulnerability": "No verification compares the actual executed step count against the declared plan before accepting a self-reported completion signal.", + "impact": "Remaining planned steps, including verification steps, are silently skipped." + }, "mitigation": { "strategy": ["validate_input", "require_human_approval"], "enforcement_point": "agent_framework", @@ -53,7 +60,7 @@ "researcher": "Faisal Haque Bappy, Tahrim Hossain, Tarannum Shaila Zaman, Raiful Hasan, Kamrul Hasan, Tariqul Islam", "researcher_url": "https://arxiv.org/abs/2608.00718", "published": "2026-08-14T00:00:00Z", - "last_updated": "2026-08-14T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "arXiv:2608.00718", diff --git a/records/AVE-2026-00080.json b/records/AVE-2026-00080.json index 0662207..d70e377 100644 --- a/records/AVE-2026-00080.json +++ b/records/AVE-2026-00080.json @@ -31,6 +31,13 @@ "trifecta_profile": { "requires": ["untrusted_content"] }, + "security_boundary": "routing position (observable, spoofable) → agent identity (should be credential-bound, is not)", + "missing_control": "no attestation or session-token check confirming a post-retry response originates from the same agent instance as before the failure", + "vulnerability_rationale": { + "capability": "An agent's identity in a multi-agent pipeline is inferred from its routing position rather than a bound credential.", + "vulnerability": "No persistent, verifiable credential binds identity to a routing position; identity is positional, not cryptographic, so anything answering at the expected slot inherits its full existing trust.", + "impact": "An adversary-controlled process that answers at the expected routing position is silently accepted as the legitimate agent, and its adversarial payload propagates downstream with the full trust the legitimate agent would have received." + }, "mitigation": { "strategy": ["verify_identity", "provenance_label"], "enforcement_point": "agent_framework", @@ -54,7 +61,7 @@ "researcher": "Faisal Haque Bappy, Tahrim Hossain, Tarannum Shaila Zaman, Raiful Hasan, Kamrul Hasan, Tariqul Islam", "researcher_url": "https://arxiv.org/abs/2608.00718", "published": "2026-08-14T00:00:00Z", - "last_updated": "2026-08-14T00:00:00Z", + "last_updated": "2026-10-31T00:00:00Z", "references": [ { "tag": "arXiv:2608.00718", diff --git a/scripts/ave_conformance.py b/scripts/ave_conformance.py index 4e1cc78..052200a 100644 --- a/scripts/ave_conformance.py +++ b/scripts/ave_conformance.py @@ -25,6 +25,9 @@ ID = re.compile(r"AVE-[0-9]{4}-[0-9]{5}") JSON_ID_KEY = re.compile(r"ave[_-]?ids?", re.IGNORECASE) RUN_PROPERTIES = ("ave_catalog", "ave_schema_version", "ave_records_sha256") +# The AVE taxonomy's SARIF identity: a taxonomy is matched by guid first, so another tool's "AVE" is not this one. +# Frozen, and equal to GUID in scripts/build_taxonomy.py (a test pins the pair). +AVE_GUID = "5110b285-34d7-5334-94db-0308b24cfb49" # What: the value if it is a dict, else an empty dict @@ -77,6 +80,32 @@ def items(self): # What: whether a parsed document is SARIF # Why: SARIF is judged against the spec; other JSON is only read for ids # How: a `runs` key, or a $schema naming SARIF (so a SARIF file whose runs array is missing is reported as such) +# What: whether a SARIF toolComponent reference names the AVE taxonomy +# Why: taxa and relationships point at a taxonomy by guid or name; a different guid means a different taxonomy +# How: a guid decides when there is one (case-insensitive); otherwise the name "AVE" +def _is_ave_component(comp): + comp = _dict(comp) + guid = comp.get("guid") + if isinstance(guid, str): + return guid.lower() == AVE_GUID + return comp.get("name") == "AVE" + + +# What: whether a reportingDescriptorReference points at an AVE class +# Why: result.taxa and rule relationships can point at any taxonomy; only AVE ids from AVE count here +# How: no toolComponent (the id pattern decides, as for result.taxa before) or an AVE component +def _is_ave_ref(ref): + comp = _dict(ref).get("toolComponent") + return comp is None or _is_ave_component(comp) + + +# What: the AVE ids a rule relates itself to, and a result tags itself with (form C) +# How: rule.relationships[].target and result.taxa[], AVE references only, in order, without repeats +def _form_c_ids(res, rule): + refs = [_dict(_dict(rel).get("target")) for rel in _list(_dict(rule).get("relationships"))] + [_dict(t) for t in _list(res.get("taxa"))] + return list(dict.fromkeys(r["id"] for r in refs if _is_id(r.get("id")) and _is_ave_ref(r))) + + def is_sarif(doc): return isinstance(doc, dict) and ("runs" in doc or "sarif" in str(doc.get("$schema", "")).lower()) @@ -158,10 +187,15 @@ def add(ave_id, via, where): add(_dict(res.get("properties")).get("ave_id"), "sarif.result.properties.ave_id", where) if len(out) == before: add(_dict(_dict(rules.get(rid)).get("properties")).get("ave_id"), "sarif.rule.properties.ave_id", where) + if len(out) == before: # form C: the tool's rule relates itself to the class + for rel in _list(_dict(rules.get(rid)).get("relationships")): + target = _dict(_dict(rel).get("target")) + if _is_id(target.get("id")) and _is_ave_ref(target): + add(target["id"], "sarif.rule.relationships", where) seen = {f["ave_id"] for f in out[before:]} for taxon in _list(res.get("taxa")): tid = _dict(taxon).get("id") - if _is_id(tid) and tid not in seen: + if _is_id(tid) and tid not in seen and _is_ave_ref(taxon): add(tid, "sarif.result.taxa", where) seen.add(tid) return out @@ -261,6 +295,10 @@ def _check_result(res, rules, where, found, require_ids): if isinstance(rid, str) and rid.startswith("AVE-") and result_id is None and rule_id is None: found.add("error", "ave_id_malformed", rid, f"{where}: ruleId {rid!r} looks like an AVE id but is not one (AVE-YYYY-NNNNN)") return + if result_id is None and rule_id is None and _form_c_ids(res, rule): # form C + if rule is None: + found.add("error", "rule_missing", rid, f"{where}: ruleId {rid!r} has no matching rules[].id") + return if result_id is None and rule_id is None: note = "" if require_ids else "; not judged, --require-ids makes this an error" found.add("error" if require_ids else "warn", "no_ave_id", rid, f"{where}: ruleId {rid!r} is not an AVE id and the result carries no properties.ave_id (AVE-in-SARIF: ruleId is the ave_id, or properties.ave_id on the result and its rule names it){note}") @@ -280,13 +318,32 @@ def _check_result(res, rules, where, found, require_ids): found.add("error", "id_mismatch", (rid, "form-b"), f"{where}: the result says {result_id!r} but its rule {rid!r} says {rule_id!r}") +# What: checks how a run points at the AVE taxonomy +# Why: a reference with the wrong guid names some other taxonomy, and a tool that uses the taxonomy should declare it +# How: rule relationships and result.taxa whose toolComponent is called AVE but carries another guid are errors; using the +# taxonomy without declaring it in driver.supportedTaxonomies is a warning +def _check_references(run, rules, n, found): + used = False + refs = [(rid, _dict(_dict(rel).get("target"))) for rid, rule in rules.items() for rel in _list(rule.get("relationships"))] + refs += [(_rule_id(_dict(res)), _dict(t)) for res in _list(run.get("results")) for t in _list(_dict(res).get("taxa"))] + for rid, ref in refs: + comp = _dict(ref.get("toolComponent")) + if comp.get("name") == "AVE" and isinstance(comp.get("guid"), str) and comp["guid"].lower() != AVE_GUID: + found.add("error", "reference_guid_mismatch", (rid, ref.get("id")), f"runs[{n}]: a reference to {ref.get('id')!r} names toolComponent AVE with guid {comp['guid']!r}, not {AVE_GUID}") + elif _is_id(ref.get("id")) and _is_ave_ref(ref): + used = True + supported = _list(_dict(_dict(run.get("tool")).get("driver")).get("supportedTaxonomies")) + if used and not any(_is_ave_component(s) or _dict(s).get("name") == "AVE" for s in supported): + found.add("warn", "supported_taxonomies_missing", n, f"runs[{n}] relates results to AVE classes but tool.driver.supportedTaxonomies does not declare the AVE taxonomy") + + # What: judges a SARIF document against docs/specs/ave-in-sarif.md # Why: to tell a tool author what the spec asks for that the output lacks # How: no runs array is an error; an empty one has nothing to judge. Per result: _check_result (errors; a result naming no # AVE class is a warning unless require_ids). Per run: the three ave_* properties (recommended, warnings), the hash against the # catalog given (warning), and the AVE taxonomy: absent (warning), `version` against ave_catalog (error when they # differ, warning when it is missing), one taxon for each class cited (warning). A SARIF with no results is a warning. -def check_sarif(doc, catalog_info=None, require_ids=False): +def check_sarif(doc, catalog_info=None, require_ids=False, records=None): found = Issues() if not isinstance(doc.get("runs"), list): return [issue("error", "sarif_no_runs", "the SARIF has no runs array, so there is nothing to judge")] @@ -306,11 +363,26 @@ def check_sarif(doc, catalog_info=None, require_ids=False): recorded = props.get("ave_records_sha256") if catalog_info and isinstance(recorded, str) and recorded.strip().lower() != catalog_info["sha256"]: found.add("warn", "catalog_sha_differs", n, f"runs[{n}] says it used records with SHA-256 {recorded}, but the catalog given has {catalog_info['sha256']}: the ids are judged against a different catalog than the run used") + _check_references(run, rules, n, found) taxonomies = _list(run.get("taxonomies")) + _list(doc.get("taxonomies")) - taxonomy = next((_dict(t) for t in taxonomies if _dict(t).get("name") == "AVE"), None) + taxonomy = next((_dict(t) for t in taxonomies if _dict(t).get("name") == "AVE" or str(_dict(t).get("guid", "")).lower() == AVE_GUID), None) if taxonomy is None: found.add("warn", "taxonomies_missing", n, f"runs[{n}] has no AVE taxonomy (recommended: taxonomies[] with name \"AVE\")") continue + guid = taxonomy.get("guid") + if guid is None: + found.add("warn", "taxonomy_guid_missing", n, f"runs[{n}]: the AVE taxonomy has no guid (recommended: {AVE_GUID}, so it cannot be confused with another taxonomy named AVE)") + elif not isinstance(guid, str) or guid.lower() != AVE_GUID: + found.add("error", "taxonomy_guid_mismatch", n, f"runs[{n}]: the AVE taxonomy guid is {guid!r}, not {AVE_GUID}") + if records is not None: + by_id = {r.get("ave_id"): r for r in records if isinstance(r, dict)} + for taxon in _list(taxonomy.get("taxa")): + taxon = _dict(taxon) + tid = taxon.get("id") + if tid not in by_id: + found.add("error", "taxon_unknown", tid, f"runs[{n}]: the AVE taxonomy lists {tid!r}, which is not in the catalog") + elif isinstance(taxon.get("name"), str) and taxon["name"] != by_id[tid].get("title"): + found.add("warn", "taxon_name_differs", tid, f"runs[{n}]: the taxon {tid} is named {taxon['name']!r}, the catalog title is {by_id[tid].get('title')!r}") catalog, version = props.get("ave_catalog"), taxonomy.get("version") if catalog == "latest" and version is not None: found.add("error", "taxonomy_version_mismatch", n, f"runs[{n}]: ave_catalog is \"latest\", which has no release, so the AVE taxonomy omits version, but it says {version!r}") @@ -338,7 +410,7 @@ def check_document(doc, records=None, catalog_info=None, file=None, require_ids= findings = extract_findings(doc) issues = [] if sarif: - issues += check_sarif(doc, catalog_info, require_ids) + issues += check_sarif(doc, catalog_info, require_ids, records) if records is None: issues.append(issue("warn", "catalog_not_supplied", "no --catalog was given, so the ids were not checked against a catalog")) else: diff --git a/scripts/build_taxonomy.py b/scripts/build_taxonomy.py new file mode 100644 index 0000000..da3dd41 --- /dev/null +++ b/scripts/build_taxonomy.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python3 +"""Build the canonical AVE taxonomy as a SARIF 2.1.0 standard-taxonomy toolComponent. + + python scripts/build_taxonomy.py # writes dist/ave-taxonomy-latest.json from dist/ave-records-latest.json + python scripts/build_taxonomy.py --check # exits 1 when the file on disk is not what the records produce + python scripts/build_taxonomy.py --release v1.3.0 --release-date 2026-11-05 --download-uri URL --out PATH + python scripts/build_taxonomy.py --only AVE-2026-00001,AVE-2026-00075 --out - # the subset a scanner embeds + +Standard library only. The output is deterministic: same records in, same bytes out. +""" +import argparse, json, re, sys, uuid +from pathlib import Path + +# The taxonomy's identity. SARIF consumers match a taxonomy by guid, so a tool that names its own taxonomy "AVE" +# is not confused with this one. Frozen: a test pins the value; changing it breaks every consumer that stored it. +GUID = "5110b285-34d7-5334-94db-0308b24cfb49" # uuid5(NAMESPACE_URL, "https://aveproject.org/taxonomy/AVE") +NAME = "AVE" +INFO_URI = "https://aveproject.org" +HELP_URI = "https://aveproject.org/registry.html#{id}" +ID = re.compile(r"AVE-[0-9]{4}-[0-9]{5}") +EXTRA = ("merged_into", "rejection_reason") # present on records only when their status needs them + + +def _version(release): + if release is None: + return None + if not re.fullmatch(r"v[0-9]+\.[0-9]+\.[0-9]+", release): + raise ValueError(f"--release must look like v1.3.0, got {release!r}") + return release[1:] + + +def taxon(rec): + aivss = rec.get("aivss") if isinstance(rec.get("aivss"), dict) else {} + props = {"status": rec.get("status"), "severity": rec.get("severity"), "aivss_score": aivss.get("aivss_score"), + "detection_stage": rec.get("detection_stage")} + for key in EXTRA: + if rec.get(key) is not None: + props[key] = rec[key] + out = {"id": rec["ave_id"], "name": rec["title"]} + if rec.get("attack_class"): + out["shortDescription"] = {"text": rec["attack_class"]} + if rec.get("behavioral_fingerprint"): + out["fullDescription"] = {"text": rec["behavioral_fingerprint"]} + out["helpUri"] = HELP_URI.format(id=rec["ave_id"]) + out["properties"] = {k: v for k, v in props.items() if v is not None} + return out + + +def build(records, release=None, release_date=None, download_uri=None, only=None): + ids = [r["ave_id"] for r in records] + if len(set(ids)) != len(ids): + raise ValueError("duplicate ave_id in the records") + wanted = None if only is None else set(only) + if wanted is not None: + unknown = sorted(wanted - set(ids)) + if unknown: + raise ValueError(f"not in the records: {', '.join(unknown)}") + chosen = sorted((r for r in records if wanted is None or r["ave_id"] in wanted), key=lambda r: r["ave_id"]) + comp = {"guid": GUID, "name": NAME, "fullName": "Agentic Vulnerability Enumeration", "organization": "AVE Project", + "product": "AVE", "informationUri": INFO_URI, + "shortDescription": {"text": "Agentic Vulnerability Enumeration: behavioral vulnerability classes for agentic AI components"}, + "language": "en", "contents": ["nonLocalizedData"], "isComprehensive": wanted is None} + version = _version(release) + if version: + comp["version"] = version + comp["semanticVersion"] = version + if release_date: + comp["releaseDateUtc"] = release_date + if download_uri: + comp["downloadUri"] = download_uri + comp["taxa"] = [taxon(r) for r in chosen] + return comp + + +def dumps(comp): + return json.dumps(comp, indent=2, ensure_ascii=False) + "\n" + + +def main(argv=None): + ap = argparse.ArgumentParser(description=__doc__.split("\n")[0]) + ap.add_argument("--records", default="dist/ave-records-latest.json") + ap.add_argument("--out", default="dist/ave-taxonomy-latest.json") + ap.add_argument("--check", action="store_true") + ap.add_argument("--release"); ap.add_argument("--release-date"); ap.add_argument("--download-uri") + ap.add_argument("--only") + a = ap.parse_args(argv) + records = json.loads(Path(a.records).read_text(encoding="utf-8")) + text = dumps(build(records, a.release, a.release_date, a.download_uri, a.only.split(",") if a.only else None)) + if a.check: + have = Path(a.out).read_text(encoding="utf-8") if Path(a.out).exists() else None + if have != text: + print(f"{a.out} is not what {a.records} produces; run: python scripts/build_taxonomy.py", file=sys.stderr) + return 1 + print(f"{a.out} matches {a.records}") + return 0 + if a.out == "-": + sys.stdout.write(text) + else: + Path(a.out).write_text(text, encoding="utf-8") + print(f"wrote {a.out}: {len(json.loads(text)['taxa'])} taxa") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tests/conformance_data/form_a.json b/tests/conformance_data/form_a.json index cd553a2..186322d 100644 --- a/tests/conformance_data/form_a.json +++ b/tests/conformance_data/form_a.json @@ -39,6 +39,7 @@ ], "taxonomies": [ { + "guid": "5110b285-34d7-5334-94db-0308b24cfb49", "name": "AVE", "version": "9.9.9", "taxa": [ diff --git a/tests/conformance_data/form_b.json b/tests/conformance_data/form_b.json index 06b2260..953893b 100644 --- a/tests/conformance_data/form_b.json +++ b/tests/conformance_data/form_b.json @@ -42,6 +42,7 @@ ], "taxonomies": [ { + "guid": "5110b285-34d7-5334-94db-0308b24cfb49", "name": "AVE", "version": "9.9.9", "taxa": [ diff --git a/tests/conformance_data/form_b_mixed.json b/tests/conformance_data/form_b_mixed.json index 82e388c..1999ffb 100644 --- a/tests/conformance_data/form_b_mixed.json +++ b/tests/conformance_data/form_b_mixed.json @@ -114,6 +114,7 @@ ], "taxonomies": [ { + "guid": "5110b285-34d7-5334-94db-0308b24cfb49", "name": "AVE", "version": "9.9.9", "taxa": [ diff --git a/tests/test_ave_conformance.py b/tests/test_ave_conformance.py index 5a47a10..43607ca 100644 --- a/tests/test_ave_conformance.py +++ b/tests/test_ave_conformance.py @@ -39,7 +39,7 @@ def messages(rep, code): def spec_examples(): - """The complete SARIF examples in docs/specs/ave-in-sarif.md (form A, then form B), read from the spec at test time so the two cannot drift.""" + """The complete SARIF examples in docs/specs/ave-in-sarif.md (form A, form B, then form C), read from the spec at test time so the two cannot drift.""" blocks = re.findall(r"```json\n(.*?)\n```", SPEC.read_text(encoding="utf-8"), flags=re.S) docs = [] for block in blocks: @@ -48,7 +48,7 @@ def spec_examples(): except ValueError: pass # a fragment, such as the taxonomies block, not a document found = [d for d in docs if isinstance(d, dict) and "runs" in d] - assert len(found) == 2, "the spec should have exactly two complete SARIF examples, form A and form B" + assert len(found) == 3, "the spec should have exactly three complete SARIF examples, form A, form B and form C" return found @@ -60,7 +60,7 @@ def write(tmp_path, name, content): # ── 1. the spec's own example ──────────────────────────────────────────────── -@pytest.mark.parametrize("n, via", [(0, "sarif.result.ruleId"), (1, "sarif.result.properties.ave_id")], ids=["form A", "form B"]) +@pytest.mark.parametrize("n, via", [(0, "sarif.result.ruleId"), (1, "sarif.result.properties.ave_id"), (2, "sarif.rule.relationships")], ids=["form A", "form B", "form C"]) def test_each_spec_example_is_conformant_against_the_catalog_it_names(n, via): records, info, issue = C.load_catalog("dist/ave-records-v1.2.0.json") assert issue is None @@ -290,12 +290,19 @@ def test_a_taxonomy_at_the_document_level_counts(): assert "taxonomies_missing" not in codes(report(doc)) -def test_a_taxonomy_not_named_ave_does_not_count(): +def test_a_taxonomy_not_named_ave_and_without_its_guid_does_not_count(): doc = load("form_a.json") doc["runs"][0]["taxonomies"][0]["name"] = "Other" + del doc["runs"][0]["taxonomies"][0]["guid"] assert codes(report(doc)) == ["taxonomies_missing"] +def test_the_guid_decides_so_a_renamed_taxonomy_with_the_ave_guid_still_counts(): + doc = load("form_a.json") + doc["runs"][0]["taxonomies"][0]["name"] = "Renamed" + assert codes(report(doc)) == [] + + def test_a_cited_class_with_no_taxon_is_a_warning(): doc = load("form_a.json") doc["runs"][0]["taxonomies"][0]["taxa"] = [{"id": "AVE-2026-90005"}] diff --git a/tests/test_ave_taxonomy_conformance.py b/tests/test_ave_taxonomy_conformance.py new file mode 100644 index 0000000..d35c73c --- /dev/null +++ b/tests/test_ave_taxonomy_conformance.py @@ -0,0 +1,164 @@ +import copy +import json +from pathlib import Path + +import pytest + +from scripts import ave_conformance as C +from scripts import build_taxonomy as bt + +DATA = Path(__file__).parent / "conformance_data" +ID1, ID2, GONE = "AVE-2026-90001", "AVE-2026-90002", "AVE-2026-90099" + + +def catalog(): + records, info, issue = C.load_catalog(DATA / "catalog.json") + assert issue is None + return records, info + + +def form_c(rule_relationships=True, result_taxa=True, supported=True, ids=(ID1,), guid=C.AVE_GUID, taxonomy=True): + """Form B's fixture turned into form C: the tool's own rule id, related to AVE classes through the taxonomy.""" + doc = json.loads((DATA / "form_b.json").read_text(encoding="utf-8")) + run = doc["runs"][0] + rule, res = run["tool"]["driver"]["rules"][0], run["results"][0] + del rule["properties"], res["properties"] + refs = [{"id": i, "toolComponent": {"name": "AVE", "guid": guid}} for i in ids] + if rule_relationships: + rule["relationships"] = [{"target": r, "kinds": ["relevant"]} for r in refs] + if result_taxa: + res["taxa"] = refs + if supported: + run["tool"]["driver"]["supportedTaxonomies"] = [{"name": "AVE", "guid": C.AVE_GUID}] + if taxonomy: + records, _ = catalog() + comp = bt.build(records, release="v9.9.9", only=list(ids)) if all(i in {r["ave_id"] for r in records} for i in ids) else run["taxonomies"][0] + comp["guid"] = guid if taxonomy is True else taxonomy + run["taxonomies"] = [comp] + else: + run["taxonomies"] = [] + return doc + + +def report(doc, with_catalog=True): + records, info = catalog() if with_catalog else (None, None) + return C.check_document(doc, records, info) + + +def codes(rep, severity=None): + return sorted(i["code"] for i in rep["issues"] if severity in (None, i["severity"])) + + +def test_the_guid_in_the_checker_is_the_one_the_generator_stamps(): + assert C.AVE_GUID == bt.GUID + + +def test_form_c_with_relationships_and_result_taxa_is_conformant(): + rep = report(form_c()) + assert rep["result"] == "pass" and codes(rep) == [] + assert {f for f in rep["extracted"]["via"]} == {"sarif.rule.relationships"} + + +def test_form_c_with_only_a_rule_relationship_extracts_the_class(): + rep = report(form_c(result_taxa=False)) + assert rep["result"] == "pass" and rep["extracted"]["via"] == {"sarif.rule.relationships": 1} + + +def test_form_c_with_only_result_taxa_is_conformant_and_says_where_it_found_the_id(): + rep = report(form_c(rule_relationships=False)) + assert rep["result"] == "pass" and rep["extracted"]["via"] == {"sarif.result.taxa": 1} + + +def test_form_c_missing_its_rule_is_an_error(): + doc = form_c() + doc["runs"][0]["tool"]["driver"]["rules"] = [] + assert "rule_missing" in codes(report(doc), "error") + + +def test_a_reference_to_an_unknown_class_is_an_error(): + rep = report(form_c(ids=(GONE,))) + assert "unknown_ave_id" in codes(rep, "error") + + +def test_a_reference_to_a_rejected_class_warns_that_it_is_not_active(): + rep = report(form_c(ids=("AVE-2026-90004",))) + assert "not_active" in codes(rep, "warn") and rep["result"] != "fail" + + +def test_a_reference_to_a_component_called_ave_with_another_guid_is_an_error_and_is_not_counted(): + rep = report(form_c(guid="00000000-0000-4000-8000-000000000000", taxonomy=C.AVE_GUID)) + assert "reference_guid_mismatch" in codes(rep, "error") + assert rep["extracted"]["count"] == 0 + + +def test_a_reference_to_another_taxonomy_is_not_an_ave_class(): + doc = form_c() + for ref in [doc["runs"][0]["results"][0]["taxa"][0], doc["runs"][0]["tool"]["driver"]["rules"][0]["relationships"][0]["target"]]: + ref["toolComponent"] = {"name": "CWE"} + rep = report(doc) + assert rep["extracted"]["count"] == 0 and "no_ave_id" in codes(rep, "warn") + + +def test_using_the_taxonomy_without_declaring_it_is_a_warning(): + rep = report(form_c(supported=False)) + assert codes(rep) == ["supported_taxonomies_missing"] and rep["result"] == "warn" + + +def test_declaring_the_taxonomy_by_name_only_is_accepted(): + doc = form_c() + doc["runs"][0]["tool"]["driver"]["supportedTaxonomies"] = [{"name": "AVE"}] + assert codes(report(doc)) == [] + + +def test_an_embedded_taxonomy_with_the_wrong_guid_is_an_error(): + doc = form_c() + doc["runs"][0]["taxonomies"][0]["guid"] = "00000000-0000-4000-8000-000000000000" + assert "taxonomy_guid_mismatch" in codes(report(doc), "error") + + +def test_an_embedded_taxonomy_without_a_guid_is_only_a_warning(): + doc = form_c() + del doc["runs"][0]["taxonomies"][0]["guid"] + rep = report(doc) + assert codes(rep) == ["taxonomy_guid_missing"] and rep["result"] == "warn" + + +def test_the_guid_comparison_ignores_case(): + doc = form_c() + doc["runs"][0]["taxonomies"][0]["guid"] = C.AVE_GUID.upper() + assert codes(report(doc)) == [] + + +def test_a_reference_with_an_upper_case_guid_still_counts_as_ave(): + doc = form_c(guid=C.AVE_GUID.upper(), taxonomy=C.AVE_GUID) + rep = report(doc) + assert rep["extracted"]["count"] == 1 and "reference_guid_mismatch" not in codes(rep) + + +def test_a_taxon_that_is_not_in_the_catalog_is_an_error(): + doc = form_c() + doc["runs"][0]["taxonomies"][0]["taxa"].append({"id": GONE, "name": "Invented"}) + assert "taxon_unknown" in codes(report(doc), "error") + + +def test_a_taxon_whose_name_is_not_the_catalog_title_is_a_warning(): + doc = form_c() + doc["runs"][0]["taxonomies"][0]["taxa"][0]["name"] = "Something else" + rep = report(doc) + assert codes(rep) == ["taxon_name_differs"] and rep["result"] == "warn" + + +def test_without_a_catalog_the_taxa_are_not_judged_against_it(): + doc = form_c() + doc["runs"][0]["taxonomies"][0]["taxa"].append({"id": GONE, "name": "Invented"}) + assert "taxon_unknown" not in codes(report(doc, with_catalog=False)) + + +def test_a_form_b_result_keeps_its_own_rule_and_is_not_confused_by_taxa(): + doc = json.loads((DATA / "form_b.json").read_text(encoding="utf-8")) + assert report(doc)["result"] == "pass" + + +def test_form_a_and_form_b_still_extract_as_before(): + assert report(json.loads((DATA / "form_a.json").read_text(encoding="utf-8")))["extracted"]["via"] == {"sarif.result.ruleId": 1} + assert report(json.loads((DATA / "form_b.json").read_text(encoding="utf-8")))["extracted"]["via"] == {"sarif.result.properties.ave_id": 1} diff --git a/tests/test_build_taxonomy.py b/tests/test_build_taxonomy.py new file mode 100644 index 0000000..1b5fcc2 --- /dev/null +++ b/tests/test_build_taxonomy.py @@ -0,0 +1,155 @@ +import copy +import hashlib +import json +import os +import urllib.request +import uuid +from pathlib import Path + +import pytest + +from scripts import ave_conformance as C +from scripts import build_taxonomy as bt + +SARIF_COMMIT = "1742a253eb654bf8a4ed7c60eaef7412b2c23553" +SARIF_SHA256 = "c3b4bb2d6093897483348925aaa73af03b3e3f4bd4ca38cef26dcb4212a2682e" +SARIF_URL = f"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/{SARIF_COMMIT}/sarif-2.1/schema/sarif-schema-2.1.0.json" +RECORDS = Path("dist/ave-records-latest.json") + + +def records(): + return json.loads(RECORDS.read_text(encoding="utf-8")) + + +def rec(i=1, **kw): + r = {"ave_id": f"AVE-2026-{i:05d}", "title": f"Class {i}", "status": "active", "severity": "HIGH", + "detection_stage": "static_detection", "attack_class": "Example - Class", "behavioral_fingerprint": "A component does a thing.", + "aivss": {"aivss_score": 7.5}} + r.update(kw) + return r + + +def sarif_schema(): + """The official OASIS schema at a pinned commit and hash. Offline, the test is skipped locally and fails in CI.""" + path = os.environ.get("SARIF_SCHEMA_FILE") + try: + data = Path(path).read_bytes() if path else urllib.request.urlopen(SARIF_URL, timeout=20).read() + except Exception as exc: + if os.environ.get("CI"): + pytest.fail(f"cannot fetch the pinned SARIF schema in CI: {exc}") + pytest.skip(f"offline: {exc}") + assert hashlib.sha256(data).hexdigest() == SARIF_SHA256, "the SARIF schema does not match the pinned hash" + return json.loads(data) + + +def log(component, guid=bt.GUID): + ref = {"id": "AVE-2026-00001", "toolComponent": {"name": "AVE", "guid": guid}} + return {"version": "2.1.0", "runs": [{ + "tool": {"driver": {"name": "example-scanner", "rules": [{"id": "r1", "relationships": [{"target": ref, "kinds": ["relevant"]}]}], + "supportedTaxonomies": [{"name": "AVE", "guid": guid}]}}, + "taxonomies": [component], + "results": [{"ruleId": "r1", "message": {"text": "m"}, "taxa": [ref]}]}]} + + +def test_the_guid_is_frozen_and_is_the_documented_derivation(): + assert bt.GUID == "5110b285-34d7-5334-94db-0308b24cfb49" + assert bt.GUID == str(uuid.uuid5(uuid.NAMESPACE_URL, "https://aveproject.org/taxonomy/AVE")) + assert C.AVE_GUID == bt.GUID + + +def test_the_committed_taxonomy_is_what_the_committed_records_produce(): + assert bt.main(["--check"]) == 0 + + +def test_check_mode_fails_when_the_file_is_stale_or_missing(tmp_path): + out = tmp_path / "t.json" + assert bt.main(["--check", "--out", str(out)]) == 1 + out.write_text("{}\n", encoding="utf-8") + assert bt.main(["--check", "--out", str(out)]) == 1 + assert bt.main(["--out", str(out)]) == 0 and bt.main(["--check", "--out", str(out)]) == 0 + + +def test_the_output_is_deterministic_and_sorted_by_id(): + rs = [rec(3), rec(1), rec(2)] + a, b = bt.dumps(bt.build(rs)), bt.dumps(bt.build(list(reversed(rs)))) + assert a == b + assert [t["id"] for t in json.loads(a)["taxa"]] == ["AVE-2026-00001", "AVE-2026-00002", "AVE-2026-00003"] + + +def test_latest_carries_no_version_because_it_has_no_release(): + comp = bt.build([rec()], release_date="2026-11-05", download_uri="https://example.org/x") + for key in ("version", "semanticVersion", "releaseDateUtc", "downloadUri"): + assert key not in comp + + +def test_a_release_carries_its_version_date_and_uri(): + comp = bt.build([rec()], release="v1.3.0", release_date="2026-11-05", download_uri="https://example.org/x") + assert (comp["version"], comp["semanticVersion"], comp["releaseDateUtc"], comp["downloadUri"]) == ("1.3.0", "1.3.0", "2026-11-05", "https://example.org/x") + + +def test_a_release_without_a_date_or_uri_omits_them_instead_of_writing_null(): + comp = bt.build([rec()], release="v1.3.0") + assert comp["version"] == "1.3.0" and "releaseDateUtc" not in comp and "downloadUri" not in comp + + +@pytest.mark.parametrize("bad", ["1.3.0", "v1.3", "v1.3.0-rc1", "latest", ""]) +def test_a_malformed_release_is_refused(bad): + with pytest.raises(ValueError): + bt.build([rec()], release=bad) + + +def test_a_subset_is_not_comprehensive_and_the_full_taxonomy_is(): + rs = [rec(1), rec(2)] + assert bt.build(rs)["isComprehensive"] is True + sub = bt.build(rs, only=["AVE-2026-00002"]) + assert sub["isComprehensive"] is False and [t["id"] for t in sub["taxa"]] == ["AVE-2026-00002"] + + +def test_an_unknown_id_in_a_subset_is_refused(): + with pytest.raises(ValueError, match="AVE-2026-00009"): + bt.build([rec(1)], only=["AVE-2026-00009"]) + + +def test_duplicate_ids_are_refused(): + with pytest.raises(ValueError, match="duplicate"): + bt.build([rec(1), rec(1)]) + + +def test_a_taxon_follows_its_record_including_a_status_that_is_not_active(): + t = bt.taxon(rec(5, status="merged", merged_into="AVE-2026-00001")) + assert t["id"] == "AVE-2026-00005" and t["name"] == "Class 5" + assert t["helpUri"] == "https://aveproject.org/registry.html#AVE-2026-00005" + assert t["properties"] == {"status": "merged", "severity": "HIGH", "aivss_score": 7.5, "detection_stage": "static_detection", "merged_into": "AVE-2026-00001"} + assert bt.taxon(rec(6, status="rejected", rejection_reason="https://example.org/d"))["properties"]["rejection_reason"] == "https://example.org/d" + assert "merged_into" not in bt.taxon(rec(7))["properties"] + + +def test_a_record_with_missing_optional_fields_still_makes_a_taxon(): + t = bt.taxon({"ave_id": "AVE-2026-00001", "title": "T"}) + assert t == {"id": "AVE-2026-00001", "name": "T", "helpUri": "https://aveproject.org/registry.html#AVE-2026-00001", "properties": {}} + + +def test_the_generator_adds_no_em_dash_of_its_own(): + comp = bt.build([rec()]) + own = {k: v for k, v in comp.items() if k != "taxa"} + assert "\u2014" not in json.dumps(own, ensure_ascii=False) + + +@pytest.mark.parametrize("kind", ["full", "subset", "release"]) +def test_the_taxonomy_in_a_sarif_log_validates_against_the_official_schema(kind): + jsonschema = pytest.importorskip("jsonschema") + v = jsonschema.Draft7Validator(sarif_schema()) + rs = records() + comp = {"full": lambda: bt.build(rs), "subset": lambda: bt.build(rs, only=["AVE-2026-00001"]), + "release": lambda: bt.build(rs, release="v1.3.0", release_date="2026-11-05", download_uri="https://example.org/a.json", only=["AVE-2026-00001"])}[kind]() + assert [e.message for e in v.iter_errors(log(comp))] == [] + + +def test_the_schema_check_is_live_because_a_broken_component_fails_it(): + jsonschema = pytest.importorskip("jsonschema") + v = jsonschema.Draft7Validator(sarif_schema()) + comp = bt.build(records(), only=["AVE-2026-00001"]) + bad = copy.deepcopy(comp); del bad["name"] + assert any("'name' is a required property" in e.message for e in v.iter_errors(log(bad))) + bad = copy.deepcopy(comp); bad["taxa"][0].pop("id") + assert any("'id' is a required property" in e.message for e in v.iter_errors(log(bad)))