From 04eb1a44c99ad678da4dc3913699bfa75ac2e74c Mon Sep 17 00:00:00 2001 From: chaksaray Date: Thu, 10 Sep 2026 05:34:25 +0700 Subject: [PATCH 1/2] feat: add AVE-2026-00081, Lingering Authority A task/subgoal/episode-scoped capability grant (tool permission, credential, access token) outlives the closure event that justified it -- nothing in the agent's runtime ties revocation to that closure, so the agent's later, unrelated turns can reuse a capability that should already be gone. Sourced from Santos-Grueiro, 'Lingering Authority: Revocable Resource-and-Effect Capabilities for Coding Agents' (arXiv:2606.22504), whose PORTICO reference monitor demonstrates the gap empirically: a non-revoking baseline permits 10/10 tested post-closure reuses and executes 6/6 forbidden effects in a deterministic stale-write audit, versus 0/10 and 0/6 under a revoking design. Drafted per issue #217 (Part 2: verify whether the expiration-shaped case is a real, uncovered gap). Part 1 of #217 was also checked -- AVE-2026-00045's real current text already draws the scoping-vs- expiration line sharply, no change needed there. Distinctness, checked by real field comparison, not label similarity: - AVE-2026-00021 / AVE-2026-00063: active bypass of a check at the moment of action. This record bypasses nothing -- the grant is legitimate and simply never re-checked against its own closure. - AVE-2026-00045: scope misuse within a still-valid grant, no elapsed time or external event required. This record is the inverse framing: used within scope, but past when closure should have ended it. - AVE-2026-00050: an undeclared registration smuggled in at session init. This record's capability was legitimately declared and granted. Framework mappings verified against primary sources directly, not corpus precedent: - owasp_mcp: MCP02 (Privilege Escalation via Scope Creep) -- its own detection checklist and remediation #3 (JIT access, revalidation for long-running tasks) name this exact gap. - owasp_asi: ASI03 (Identity and Privilege Abuse) -- its own Common Example #4 is literally 'Time-of-Check to Time-of-Use (TOCTOU) in Agent Workflows', read directly from the primary 2026 PDF. - mitre_atlas / nist_ai_rmf: checked directly (live ATLAS.yaml; NIST AI 100-1 Tables 1-4) and left empty -- no clean fit at this mechanism's granularity, documented in aivss.notes rather than forced. id confirmed via issue #268. Includes: - records/AVE-2026-00081.json - tests/fixtures/AVE-2026-00081_{positive,negative}.md - dist/ave-records-latest.json, .manifest.json (rebuilt from a clean copy of git-tracked records + this one, to avoid pulling in another session's concurrent, unreviewed work sitting untracked in the same working directory) - CHANGELOG.md, README.md (record count, badge, table row) Validated: python3 scripts/validate_records.py (82/82 -- includes the concurrent session's untracked record on disk, harmless to the check), check_fixtures.py, check_vulnerability_taxonomy.py --strict --only, check_framework_sources.py --strict --only, write_verification_basis.py, pytest tests/ -x -q (478 passed). --- CHANGELOG.md | 16 +++ README.md | 7 +- dist/ave-records-latest.json | 121 ++++++++++++++++++++++ dist/ave-records-latest.manifest.json | 4 +- records/AVE-2026-00081.json | 121 ++++++++++++++++++++++ tests/fixtures/AVE-2026-00081_negative.md | 35 +++++++ tests/fixtures/AVE-2026-00081_positive.md | 32 ++++++ 7 files changed, 331 insertions(+), 5 deletions(-) create mode 100644 records/AVE-2026-00081.json create mode 100644 tests/fixtures/AVE-2026-00081_negative.md create mode 100644 tests/fixtures/AVE-2026-00081_positive.md diff --git a/CHANGELOG.md b/CHANGELOG.md index b7fee85..627cd63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -68,6 +68,22 @@ Format: [Semantic Versioning](https://semver.org). Schema versions and record se new record. ### Added +- AVE-2026-00081: Lingering authority — a task/subgoal/episode-scoped + capability grant outlives the closure event that justified it, with + nothing in the agent's runtime tying revocation to that closure, so + the agent's later, unrelated turns can reuse it. Sourced from + Santos-Grueiro, "Lingering Authority: Revocable Resource-and-Effect + Capabilities for Coding Agents" (arXiv:2606.22504), whose PORTICO + reference monitor demonstrates the gap empirically: a non-revoking + baseline permits 10/10 post-closure reuses and 6/6 forbidden effects + in a deterministic stale-write audit, versus 0/10 and 0/6 under a + revoking design. Distinct from AVE-2026-00021/00063 (active bypass + of a check, not this record's un-rechecked legitimate grant), from + AVE-2026-00045 (scope misuse within a still-valid grant, no elapsed + time or event required, versus this record's temporal/lifecycle + framing), and from AVE-2026-00050 (an undeclared registration, not + this record's legitimately-granted-but-unrevoked capability). Id + confirmed via issue #268 (MEDIUM, AIVSS 6.1). - AVE-2026-00078, 00079, 00080: three genuinely distinct multi-agent pipeline mechanisms extracted from Bappy et al., "Adversarial Attacks in Multi-Agent LLM Pipelines: Unveiling Structural Vulnerabilities in diff --git a/README.md b/README.md index 987a272..122c98d 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Stable IDs, AIVSS scores, and behavioral fingerprints for every way a skill file MCP server, system prompt, or agent plugin can be weaponized — scored consistently, mapped to the frameworks security teams already report against. -[![Records](https://img.shields.io/badge/records-80-0f6e56?style=flat-square)](records/) +[![Records](https://img.shields.io/badge/records-81-0f6e56?style=flat-square)](records/) [![Schema](https://img.shields.io/badge/schema-v1.1.0-0a3024?style=flat-square)](schema/ave-record-1.1.0.schema.json) [![AIVSS](https://img.shields.io/badge/AIVSS-v0.8-d4a017?style=flat-square)](https://aivss.owasp.org) [![OWASP MCP](https://img.shields.io/badge/OWASP-MCP%20Top%2010-0a3024?style=flat-square)](https://owasp.org) @@ -102,7 +102,7 @@ two published AVE records, corrected the underlying process documentation, not just the two records, credited in [CONTRIBUTORS.md](CONTRIBUTORS.md). -80 records. 8 independent crosswalks. See +81 records. 8 independent crosswalks. See [crosswalks/](crosswalks/) for the full mappings, and [docs/writeups/](docs/writeups/) for full technical write-ups on individual records. @@ -208,7 +208,7 @@ AIVSS = ((8.5 + 7.5) / 2) x 1.0 x 1 = 8.0 -> HIGH ## Record index
-80 records, click to expand +81 records, click to expand | AVE ID | Title | AIVSS | Severity | |---|---|---|---| @@ -292,6 +292,7 @@ AIVSS = ((8.5 + 7.5) / 2) x 1.0 x 1 = 8.0 -> HIGH | [AVE-2026-00078](records/AVE-2026-00078.json) | Consensus Poisoning: Unverified Multi-Agent Result Acceptance | 6.4 | MEDIUM | | [AVE-2026-00079](records/AVE-2026-00079.json) | Plan Hijacking via False Completion Signal | 6.2 | MEDIUM | | [AVE-2026-00080](records/AVE-2026-00080.json) | Silent Agent Substitution (Sybil) via Unverified Retry | 6.8 | MEDIUM | +| [AVE-2026-00081](records/AVE-2026-00081.json) | Lingering Authority: Stale Capability Survives Episode Closure | 6.1 | MEDIUM |
diff --git a/dist/ave-records-latest.json b/dist/ave-records-latest.json index fb74f20..6f971be 100644 --- a/dist/ave-records-latest.json +++ b/dist/ave-records-latest.json @@ -10815,6 +10815,127 @@ } } }, + { + "ave_id": "AVE-2026-00081", + "schema_version": "1.1.0", + "status": "active", + "title": "Lingering authority: a task-scoped capability outlives the episode that justified it", + "attack_class": "Persistence - Lingering Authority", + "severity": "MEDIUM", + "description": "An agent is granted a temporary resource or effect capability -- a tool permission, credential, or access token -- scoped to a specific task, subgoal, or episode. That episode closes (the subgoal completes, a task ends, an incident resolves, an approval window expires) but nothing in the agent's runtime ties the capability's revocation to that closure event, so the capability remains structurally valid and reusable. The agent's own later turns in the same session -- or an attacker who can extend, race, or mimic the closure signal -- continue to invoke the stale capability for actions the now-closed episode no longer justifies, executing writes, mutations, or network egress the current task has no standing to authorize. Distinct from AVE-2026-00021 (Human-in-Loop Bypass) and AVE-2026-00063 (Approval Gate Bypass Configuration): those records describe actively bypassing a confirmation or approval check at the moment of action, via instruction or config. This record involves no bypass of any check -- the grant was legitimately issued and nothing re-checks it when its own justifying condition ends. Distinct from AVE-2026-00045 (Cross-App-Access Escalation): that record's grant is legitimately used, unexpired, for a purpose outside its scope, within a single session with no elapsed time or external event required. Here the grant is used within its originally intended purpose, but past the point where a real external, checkable event (episode closure) should have ended it -- the inverse framing: temporal and lifecycle, not scope. Distinct from AVE-2026-00050 (Parasitic Toolchain): that record smuggles in an undeclared registration beyond manifest scope at session init. Here the capability was legitimately declared and granted; the failure is purely a missing closure-triggered revocation. First formalized and measured by PORTICO (arXiv:2606.22504), whose non-revoking baseline permitted all 10 of 10 tested post-closure capability reuses and executed 6 of 6 forbidden effects (file writes, git mutation, network egress) in a deterministic stale-write audit, versus 0 of 10 and 0 of 6 respectively under a revoking reference monitor with the same initial grants at the same turns.", + "aivss_score": 6.1, + "cvss_base_vector": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:L/SC:H/SI:H/SA:L", + "owasp_mcp": [ + "MCP02" + ], + "owasp_asi": [ + "ASI03" + ], + "mitre_atlas": [], + "nist_ai_rmf": [], + "behavioral_fingerprint": "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.", + "behavioral_vector": [ + "capability-lifecycle", + "stale-authorization", + "closure-triggered-revocation-gap", + "toctou" + ], + "provenance_vector": { + "entry_class": "runtime", + "payload_surface": "a task/subgoal/episode-scoped capability handle (tool permission, credential, or access grant) retained in the agent's own runtime/session state after that episode's closure event, with no mechanism binding its revocation to that closure" + }, + "security_boundary": "closed-episode authorization to continued autonomous action", + "missing_control": "no closure-triggered revocation binding a capability grant to the episode that justified it", + "vulnerability_rationale": { + "capability": "The agent can invoke a tool, file-write, git-mutation, or network-egress capability that was granted for a specific task, subgoal, or episode.", + "vulnerability": "Nothing in the agent's runtime ties that capability's revocation to the closure of the episode that justified it, so the capability remains structurally valid and reusable after its justifying condition has already ended.", + "impact": "The agent, or an attacker able to extend or race the closure signal, executes writes, mutations, or network egress that the current, later task has no standing to authorize, using access that should already have been revoked." + }, + "mitigation": { + "strategy": [ + "isolate_scope", + "least_privilege", + "deny_by_default" + ], + "enforcement_point": "agent_framework", + "trifecta_control": "not_applicable" + }, + "example_patterns": [ + "Coding agent is granted write access to a specific file for one subtask; after that subtask's own completion is logged, the agent uses the same still-valid write handle to modify an unrelated file later in the same session, with no new grant issued for it.", + "An agent is granted temporary elevated access scoped to resolving an open incident; the incident is marked resolved mid-session, but the agent's next several tool calls continue to use the same elevated grant for unrelated work with no revocation event in between.", + "A procurement agent validates a spending authorization at the start of a purchase workflow; the user's authorization is reduced hours later, but the workflow completes the transaction using the original, now-stale authorization token." + ], + "mutation_count": 0, + "detection_methodology": "1. Reconstruct the session's capability-grant timeline: every capability, credential, or access-token grant, the task/subgoal/episode it was scoped to, and that episode's own completion, resolution, or closure event. 2. For each closure event, check every subsequent tool call, file write, git mutation, or network request in the same session for use of a capability handle that was scoped to the now-closed episode. 3. Flag any such use where no revocation, re-grant, or re-authorization event is recorded between the closure and the reuse. 4. Confirm the reused capability was not independently re-justified by a new, later grant covering the same handle -- a fresh grant for the same access is not this class.", + "indicators_of_compromise": [ + "A tool call, file write, git mutation, or network request executes using a capability, credential, or grant handle that was issued for a task, subgoal, or episode whose own completion, resolution, or closure event is already recorded earlier in the same session log, with no intervening re-grant or revocation entry between the two.", + "Session or audit logs contain a task-completion, ticket-resolution, or incident-closure event with no corresponding capability-revocation, token-invalidation, or deny-rule entry logged at or immediately after that event.", + "The same capability handle or access token appears in tool-call logs across two or more unrelated, sequential subgoals within one session, with no re-grant or re-authorization event recorded between them." + ], + "remediation": "Bind every temporary capability grant to the specific episode, subgoal, or task contract that justified issuing it, using an explicit request-grant-invoke lifecycle: compile the task contract into initial capabilities and trusted closure predicates, materialize any expansion as an opaque, epoch-bound handle, and remove that handle from the planner's next interface the moment its own closure predicate fires, rejecting any subsequent replay of the retired handle before it can reach a side-effecting tool call. Do not rely on session-level or blanket task-level access scoping alone; require re-validation or a fresh grant for any capability use that follows a detected closure event, matching PORTICO's own evaluated design (arXiv:2606.22504).", + "kill_switch_active": false, + "researcher": "Igor Santos-Grueiro", + "researcher_url": "https://arxiv.org/abs/2606.22504", + "published": "2026-09-09T00:00:00Z", + "last_updated": "2026-09-09T00:00:00Z", + "references": [ + { + "tag": "arXiv:2606.22504", + "text": "Santos-Grueiro, Igor. 'Lingering Authority: Revocable Resource-and-Effect Capabilities for Coding Agents.' cs.CR, submitted 2026-06-21. Coins 'lingering authority' and proposes PORTICO, a reference monitor implementing a request-grant-invoke capability lifecycle with epoch-bound handles and closure-triggered revocation. A non-revoking comparator permits 10/10 tested post-closure capability reuses and executes 6/6 forbidden effects (file writes, git mutation, network egress) in a deterministic stale-write audit, versus 0/10 and 0/6 under PORTICO, with both systems matching on task success, scope compliance, and all pre-closure decisions.", + "url": "https://arxiv.org/abs/2606.22504" + }, + { + "tag": "AVE issue #268", + "text": "ave_id AVE-2026-00081 confirmed via the id-confirmation issue, including the distinctness comparison against AVE-2026-00021, AVE-2026-00045, AVE-2026-00050, and AVE-2026-00063, and the primary-source framework mappings.", + "url": "https://github.com/aveproject/ave/issues/268" + } + ], + "aivss": { + "cvss_base": 8, + "aarf": { + "autonomy": 1, + "tool_use": 1, + "multi_agent": 0, + "non_determinism": 0.5, + "self_modification": 0, + "dynamic_identity": 0, + "persistent_memory": 1, + "natural_language_input": 0.5, + "data_access": 1, + "external_dependencies": 0.5 + }, + "aars": 5.5, + "thm": 0.9, + "mitigation_factor": 1, + "aivss_score": 6.1, + "aivss_severity": "MEDIUM", + "spec_version": "0.8", + "notes": "persistent_memory and data_access scored at maximum (1): the entire mechanism is a capability persisting in the agent's own runtime state across what should have been a hard boundary, and the worst-case reuse is typically against files, credentials, or other sensitive data the grant covers. autonomy and tool_use also at maximum: the reuse happens with no human confirmation, and the mechanism is definitionally about tool/resource access. multi_agent, self_modification, and dynamic_identity scored 0: the mechanism is single-agent and does not require the component to alter its own instructions or assume a different persona. non_determinism and natural_language_input scored 0.5: whether an episode's closure is correctly detected can vary run to run (especially where closure is inferred from a natural-language completion claim rather than a structured event), but the core failure -- no closure-triggered revocation -- is structural, not language-driven, so neither extreme fit cleanly. external_dependencies scored 0.5: one of the paper's three tested effect classes is network egress, but exploitability of that specific effect depends on what the granted capability actually covers. thm set to 0.90 (PoC exists, not yet exploited in the wild): PORTICO's own evaluation is a real, working, measured demonstration (scripted traces, six live model traces, frozen real-repository runs with recorded commits), not a theoretical scenario, but there is no disclosed in-the-wild incident yet. mitigation_factor set to 1 (no broad ecosystem-wide mitigation exists yet): PORTICO is a novel 2026 research design, not yet a widely adopted standard fix. owasp_mcp mapped to MCP02 (Privilege Escalation via Scope Creep) after reading the category's full primary-source text (github.com/OWASP/www-project-mcp-top-10, 2025/MCP02 document, commit 165fe0f78ef104459237b4a8e0f6e78db9b02391): its detection checklist names 'no enforced expiration for scopes or tokens' verbatim, and its own remediation #3 ('Expiry-Based & Just-in-Time (JIT) Access... require revalidation for long-running or recurring tasks') is the same gap this record describes, even though MCP02's top-line description frames the more general case as privileges expanding rather than failing to contract. MCP07 (Insufficient Authentication & Authorization) was also checked and rejected: its own text is about authentication/identity verification and cross-agent token reuse, not episode-closure-triggered revocation specifically. owasp_asi mapped to ASI03 (Identity and Privilege Abuse) after reading the actual 2026 PDF directly (genai.owasp.org/resource/owasp-top-10-for-agentic-applications-for-2026, pages 15-16): Common Example of the Vulnerability #4 is literally 'Time-of-Check to Time-of-Use (TOCTOU) in Agent Workflows... Permissions may be validated at the start of a workflow but change or expire before execution. The agent continues with outdated authorization,' and Example Attack Scenario #5 ('Workflow Authorization Drift') describes the same mechanism verbatim in worked form. mitre_atlas confirmed empty: swept the live ATLAS.yaml (mitre-atlas/atlas-data, 170+ techniques) directly for stale/expired/revalidation/TOCTOU/closure language; the only hit, AML.T0091.000 (Application Access Token), describes an adversary using a *stolen* token to bypass authentication -- a different mechanism (credential theft) from a legitimately-issued grant the agent's own runtime fails to revoke. A genuine gap, not an unresearched omission. nist_ai_rmf confirmed empty: checked the actual NIST AI 100-1 text (Tables 1-4) directly; MANAGE-2.4 ('mechanisms... to supersede, disengage, or deactivate AI systems that demonstrate performance or outcomes inconsistent with intended use') and GOVERN-1.7 (decommissioning AI systems) are the closest, but both operate at whole-AI-system deactivation/decommissioning granularity, not per-capability, per-episode revocation. Neither is a clean fit at the granularity this class describes." + }, + "evidence_kind_default": "behavioral_pattern", + "detection_stage": "runtime_observed", + "detection_layer": "runtime", + "confidence_baseline": 0.6, + "evidence_basis_engines": [ + "llm", + "sandbox" + ], + "derivable_into": [ + "privilege-escalation-chain" + ], + "framework_sources": { + "owasp_mcp": { + "commit": "165fe0f78ef104459237b4a8e0f6e78db9b02391", + "read_date": "2026-09-09", + "source_url": "https://github.com/OWASP/www-project-mcp-top-10/blob/165fe0f78ef104459237b4a8e0f6e78db9b02391/2025/MCP02-2025%E2%80%93Privilege-Escalation-via-Scope-Creep.md" + }, + "owasp_asi": { + "version": "2026", + "read_date": "2026-09-09", + "source_url": "https://genai.owasp.org/resource/owasp-top-10-for-agentic-applications-for-2026/" + } + } + }, { "ave_id": "AVE-2026-00014", "schema_version": "1.1.0", diff --git a/dist/ave-records-latest.manifest.json b/dist/ave-records-latest.manifest.json index 5eb5404..9a497fa 100644 --- a/dist/ave-records-latest.manifest.json +++ b/dist/ave-records-latest.manifest.json @@ -1,6 +1,6 @@ { "schema_version": "1.1.0", - "record_count": 80, - "generated_at": "2026-09-04T23:32:41.508Z", + "record_count": 81, + "generated_at": "2026-09-09T16:04:56.397Z", "source": "https://github.com/aveproject/ave" } diff --git a/records/AVE-2026-00081.json b/records/AVE-2026-00081.json new file mode 100644 index 0000000..ab807f4 --- /dev/null +++ b/records/AVE-2026-00081.json @@ -0,0 +1,121 @@ +{ + "ave_id": "AVE-2026-00081", + "schema_version": "1.1.0", + "status": "active", + "title": "Lingering authority: a task-scoped capability outlives the episode that justified it", + "attack_class": "Persistence - Lingering Authority", + "severity": "MEDIUM", + "description": "An agent is granted a temporary resource or effect capability -- a tool permission, credential, or access token -- scoped to a specific task, subgoal, or episode. That episode closes (the subgoal completes, a task ends, an incident resolves, an approval window expires) but nothing in the agent's runtime ties the capability's revocation to that closure event, so the capability remains structurally valid and reusable. The agent's own later turns in the same session -- or an attacker who can extend, race, or mimic the closure signal -- continue to invoke the stale capability for actions the now-closed episode no longer justifies, executing writes, mutations, or network egress the current task has no standing to authorize. Distinct from AVE-2026-00021 (Human-in-Loop Bypass) and AVE-2026-00063 (Approval Gate Bypass Configuration): those records describe actively bypassing a confirmation or approval check at the moment of action, via instruction or config. This record involves no bypass of any check -- the grant was legitimately issued and nothing re-checks it when its own justifying condition ends. Distinct from AVE-2026-00045 (Cross-App-Access Escalation): that record's grant is legitimately used, unexpired, for a purpose outside its scope, within a single session with no elapsed time or external event required. Here the grant is used within its originally intended purpose, but past the point where a real external, checkable event (episode closure) should have ended it -- the inverse framing: temporal and lifecycle, not scope. Distinct from AVE-2026-00050 (Parasitic Toolchain): that record smuggles in an undeclared registration beyond manifest scope at session init. Here the capability was legitimately declared and granted; the failure is purely a missing closure-triggered revocation. First formalized and measured by PORTICO (arXiv:2606.22504), whose non-revoking baseline permitted all 10 of 10 tested post-closure capability reuses and executed 6 of 6 forbidden effects (file writes, git mutation, network egress) in a deterministic stale-write audit, versus 0 of 10 and 0 of 6 respectively under a revoking reference monitor with the same initial grants at the same turns.", + "aivss_score": 6.1, + "cvss_base_vector": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:L/SC:H/SI:H/SA:L", + "owasp_mcp": [ + "MCP02" + ], + "owasp_asi": [ + "ASI03" + ], + "mitre_atlas": [], + "nist_ai_rmf": [], + "behavioral_fingerprint": "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.", + "behavioral_vector": [ + "capability-lifecycle", + "stale-authorization", + "closure-triggered-revocation-gap", + "toctou" + ], + "provenance_vector": { + "entry_class": "runtime", + "payload_surface": "a task/subgoal/episode-scoped capability handle (tool permission, credential, or access grant) retained in the agent's own runtime/session state after that episode's closure event, with no mechanism binding its revocation to that closure" + }, + "security_boundary": "closed-episode authorization to continued autonomous action", + "missing_control": "no closure-triggered revocation binding a capability grant to the episode that justified it", + "vulnerability_rationale": { + "capability": "The agent can invoke a tool, file-write, git-mutation, or network-egress capability that was granted for a specific task, subgoal, or episode.", + "vulnerability": "Nothing in the agent's runtime ties that capability's revocation to the closure of the episode that justified it, so the capability remains structurally valid and reusable after its justifying condition has already ended.", + "impact": "The agent, or an attacker able to extend or race the closure signal, executes writes, mutations, or network egress that the current, later task has no standing to authorize, using access that should already have been revoked." + }, + "mitigation": { + "strategy": [ + "isolate_scope", + "least_privilege", + "deny_by_default" + ], + "enforcement_point": "agent_framework", + "trifecta_control": "not_applicable" + }, + "example_patterns": [ + "Coding agent is granted write access to a specific file for one subtask; after that subtask's own completion is logged, the agent uses the same still-valid write handle to modify an unrelated file later in the same session, with no new grant issued for it.", + "An agent is granted temporary elevated access scoped to resolving an open incident; the incident is marked resolved mid-session, but the agent's next several tool calls continue to use the same elevated grant for unrelated work with no revocation event in between.", + "A procurement agent validates a spending authorization at the start of a purchase workflow; the user's authorization is reduced hours later, but the workflow completes the transaction using the original, now-stale authorization token." + ], + "mutation_count": 0, + "detection_methodology": "1. Reconstruct the session's capability-grant timeline: every capability, credential, or access-token grant, the task/subgoal/episode it was scoped to, and that episode's own completion, resolution, or closure event. 2. For each closure event, check every subsequent tool call, file write, git mutation, or network request in the same session for use of a capability handle that was scoped to the now-closed episode. 3. Flag any such use where no revocation, re-grant, or re-authorization event is recorded between the closure and the reuse. 4. Confirm the reused capability was not independently re-justified by a new, later grant covering the same handle -- a fresh grant for the same access is not this class.", + "indicators_of_compromise": [ + "A tool call, file write, git mutation, or network request executes using a capability, credential, or grant handle that was issued for a task, subgoal, or episode whose own completion, resolution, or closure event is already recorded earlier in the same session log, with no intervening re-grant or revocation entry between the two.", + "Session or audit logs contain a task-completion, ticket-resolution, or incident-closure event with no corresponding capability-revocation, token-invalidation, or deny-rule entry logged at or immediately after that event.", + "The same capability handle or access token appears in tool-call logs across two or more unrelated, sequential subgoals within one session, with no re-grant or re-authorization event recorded between them." + ], + "remediation": "Bind every temporary capability grant to the specific episode, subgoal, or task contract that justified issuing it, using an explicit request-grant-invoke lifecycle: compile the task contract into initial capabilities and trusted closure predicates, materialize any expansion as an opaque, epoch-bound handle, and remove that handle from the planner's next interface the moment its own closure predicate fires, rejecting any subsequent replay of the retired handle before it can reach a side-effecting tool call. Do not rely on session-level or blanket task-level access scoping alone; require re-validation or a fresh grant for any capability use that follows a detected closure event, matching PORTICO's own evaluated design (arXiv:2606.22504).", + "kill_switch_active": false, + "researcher": "Igor Santos-Grueiro", + "researcher_url": "https://arxiv.org/abs/2606.22504", + "published": "2026-09-09T00:00:00Z", + "last_updated": "2026-09-09T00:00:00Z", + "references": [ + { + "tag": "arXiv:2606.22504", + "text": "Santos-Grueiro, Igor. 'Lingering Authority: Revocable Resource-and-Effect Capabilities for Coding Agents.' cs.CR, submitted 2026-06-21. Coins 'lingering authority' and proposes PORTICO, a reference monitor implementing a request-grant-invoke capability lifecycle with epoch-bound handles and closure-triggered revocation. A non-revoking comparator permits 10/10 tested post-closure capability reuses and executes 6/6 forbidden effects (file writes, git mutation, network egress) in a deterministic stale-write audit, versus 0/10 and 0/6 under PORTICO, with both systems matching on task success, scope compliance, and all pre-closure decisions.", + "url": "https://arxiv.org/abs/2606.22504" + }, + { + "tag": "AVE issue #268", + "text": "ave_id AVE-2026-00081 confirmed via the id-confirmation issue, including the distinctness comparison against AVE-2026-00021, AVE-2026-00045, AVE-2026-00050, and AVE-2026-00063, and the primary-source framework mappings.", + "url": "https://github.com/aveproject/ave/issues/268" + } + ], + "aivss": { + "cvss_base": 8.0, + "aarf": { + "autonomy": 1, + "tool_use": 1, + "multi_agent": 0, + "non_determinism": 0.5, + "self_modification": 0, + "dynamic_identity": 0, + "persistent_memory": 1, + "natural_language_input": 0.5, + "data_access": 1, + "external_dependencies": 0.5 + }, + "aars": 5.5, + "thm": 0.9, + "mitigation_factor": 1, + "aivss_score": 6.1, + "aivss_severity": "MEDIUM", + "spec_version": "0.8", + "notes": "persistent_memory and data_access scored at maximum (1): the entire mechanism is a capability persisting in the agent's own runtime state across what should have been a hard boundary, and the worst-case reuse is typically against files, credentials, or other sensitive data the grant covers. autonomy and tool_use also at maximum: the reuse happens with no human confirmation, and the mechanism is definitionally about tool/resource access. multi_agent, self_modification, and dynamic_identity scored 0: the mechanism is single-agent and does not require the component to alter its own instructions or assume a different persona. non_determinism and natural_language_input scored 0.5: whether an episode's closure is correctly detected can vary run to run (especially where closure is inferred from a natural-language completion claim rather than a structured event), but the core failure -- no closure-triggered revocation -- is structural, not language-driven, so neither extreme fit cleanly. external_dependencies scored 0.5: one of the paper's three tested effect classes is network egress, but exploitability of that specific effect depends on what the granted capability actually covers. thm set to 0.90 (PoC exists, not yet exploited in the wild): PORTICO's own evaluation is a real, working, measured demonstration (scripted traces, six live model traces, frozen real-repository runs with recorded commits), not a theoretical scenario, but there is no disclosed in-the-wild incident yet. mitigation_factor set to 1 (no broad ecosystem-wide mitigation exists yet): PORTICO is a novel 2026 research design, not yet a widely adopted standard fix. owasp_mcp mapped to MCP02 (Privilege Escalation via Scope Creep) after reading the category's full primary-source text (github.com/OWASP/www-project-mcp-top-10, 2025/MCP02 document, commit 165fe0f78ef104459237b4a8e0f6e78db9b02391): its detection checklist names 'no enforced expiration for scopes or tokens' verbatim, and its own remediation #3 ('Expiry-Based & Just-in-Time (JIT) Access... require revalidation for long-running or recurring tasks') is the same gap this record describes, even though MCP02's top-line description frames the more general case as privileges expanding rather than failing to contract. MCP07 (Insufficient Authentication & Authorization) was also checked and rejected: its own text is about authentication/identity verification and cross-agent token reuse, not episode-closure-triggered revocation specifically. owasp_asi mapped to ASI03 (Identity and Privilege Abuse) after reading the actual 2026 PDF directly (genai.owasp.org/resource/owasp-top-10-for-agentic-applications-for-2026, pages 15-16): Common Example of the Vulnerability #4 is literally 'Time-of-Check to Time-of-Use (TOCTOU) in Agent Workflows... Permissions may be validated at the start of a workflow but change or expire before execution. The agent continues with outdated authorization,' and Example Attack Scenario #5 ('Workflow Authorization Drift') describes the same mechanism verbatim in worked form. mitre_atlas confirmed empty: swept the live ATLAS.yaml (mitre-atlas/atlas-data, 170+ techniques) directly for stale/expired/revalidation/TOCTOU/closure language; the only hit, AML.T0091.000 (Application Access Token), describes an adversary using a *stolen* token to bypass authentication -- a different mechanism (credential theft) from a legitimately-issued grant the agent's own runtime fails to revoke. A genuine gap, not an unresearched omission. nist_ai_rmf confirmed empty: checked the actual NIST AI 100-1 text (Tables 1-4) directly; MANAGE-2.4 ('mechanisms... to supersede, disengage, or deactivate AI systems that demonstrate performance or outcomes inconsistent with intended use') and GOVERN-1.7 (decommissioning AI systems) are the closest, but both operate at whole-AI-system deactivation/decommissioning granularity, not per-capability, per-episode revocation. Neither is a clean fit at the granularity this class describes." + }, + "evidence_kind_default": "behavioral_pattern", + "detection_stage": "runtime_observed", + "detection_layer": "runtime", + "confidence_baseline": 0.6, + "evidence_basis_engines": [ + "llm", + "sandbox" + ], + "derivable_into": [ + "privilege-escalation-chain" + ], + "framework_sources": { + "owasp_mcp": { + "commit": "165fe0f78ef104459237b4a8e0f6e78db9b02391", + "read_date": "2026-09-09", + "source_url": "https://github.com/OWASP/www-project-mcp-top-10/blob/165fe0f78ef104459237b4a8e0f6e78db9b02391/2025/MCP02-2025%E2%80%93Privilege-Escalation-via-Scope-Creep.md" + }, + "owasp_asi": { + "version": "2026", + "read_date": "2026-09-09", + "source_url": "https://genai.owasp.org/resource/owasp-top-10-for-agentic-applications-for-2026/" + } + } +} diff --git a/tests/fixtures/AVE-2026-00081_negative.md b/tests/fixtures/AVE-2026-00081_negative.md new file mode 100644 index 0000000..c4018b1 --- /dev/null +++ b/tests/fixtures/AVE-2026-00081_negative.md @@ -0,0 +1,35 @@ +# Session log: incident-response agent, capability correctly revoked at closure + +Agent is granted elevated write access to the production config repo, +scoped explicitly to resolving `INC-4471`. + +``` +[09:12:03] grant: capability=repo:write:prod-config, scope=INC-4471, + issued_for=incident_response + +[09:14:41] tool_call: repo:write(prod-config, "disable_feature_flag: checkout_v2") + capability=repo:write:prod-config -> OK (scope=INC-4471, still open) + +[09:22:17] event: INC-4471 status=RESOLVED, closed_by=oncall_human + +[09:22:18] revoke: capability=repo:write:prod-config, reason=incident_closed + +[09:41:05] tool_call: repo:write(prod-config, "enable_feature_flag: checkout_v3_beta") + capability=repo:write:prod-config -> DENIED (capability revoked at 09:22:18) + +[09:41:09] grant: capability=repo:write:prod-config, scope=REQ-8820, + issued_for=feature_rollout, approved_by=release_manager + +[09:41:12] tool_call: repo:write(prod-config, "enable_feature_flag: checkout_v3_beta") + capability=repo:write:prod-config -> OK (scope=REQ-8820, freshly granted) +``` + +The closure of `INC-4471` at `09:22:17` is immediately followed by an +explicit revoke of the capability it justified. The later, +unrelated write at `09:41:12` succeeds only after an independent, +freshly issued grant scoped to a different, newly opened request +(`REQ-8820`) -- not a reuse of the retired handle. A conforming +implementation must not flag this: the closure-triggered revocation +this class is about is exactly the control present here, and the +capability that executes the second write is not the stale one, it is +a new grant with its own justification. diff --git a/tests/fixtures/AVE-2026-00081_positive.md b/tests/fixtures/AVE-2026-00081_positive.md new file mode 100644 index 0000000..a1d892a --- /dev/null +++ b/tests/fixtures/AVE-2026-00081_positive.md @@ -0,0 +1,32 @@ +# Session log: incident-response agent, capability outlives incident closure + +Agent is granted elevated write access to the production config repo, +scoped explicitly to resolving `INC-4471`. + +``` +[09:12:03] grant: capability=repo:write:prod-config, scope=INC-4471, + issued_for=incident_response + +[09:14:41] tool_call: repo:write(prod-config, "disable_feature_flag: checkout_v2") + capability=repo:write:prod-config -> OK (scope=INC-4471, still open) + +[09:22:17] event: INC-4471 status=RESOLVED, closed_by=oncall_human + +[09:22:18] (no revoke, deny, or re-grant event logged for + capability=repo:write:prod-config) + +[09:41:05] tool_call: repo:write(prod-config, "enable_feature_flag: checkout_v3_beta") + capability=repo:write:prod-config -> OK + # note: unrelated to INC-4471; agent is now handling a + # separate, later user request in the same session +``` + +The `repo:write:prod-config` capability was issued for, and used within, +the scope of `INC-4471`. Once `INC-4471` closes at `09:22:17`, nothing in +the session revokes, expires, or re-validates that capability. The +`09:41:05` write is unrelated to the incident that justified the grant, +executed nearly twenty minutes after the justifying condition ended, +using the same still-valid handle with no intervening re-grant. No +approval-bypass, no false role claim, no undeclared registration -- +the grant was legitimate throughout; the gap is purely that its own +closure event never triggered revocation. From 94cfe10e9d6a2d68f7e72494a16d6e9b5496e552 Mon Sep 17 00:00:00 2001 From: chaksaray Date: Wed, 16 Sep 2026 06:57:17 +0700 Subject: [PATCH 2/2] docs: add generated-file submission check to crosswalk discipline Section 4 of scaling-and-governance.md becomes 'Crosswalk discipline' with two subsections: 4.1 is the existing numbering-caution text, unchanged. New 4.2 requires checking whether a target repo's file is generated before proposing content into it, finding the project's own registration mechanism if so, and running the generator locally before opening anything. Prompted by GenAI-Security-Project/GenAI-Data-Security-Initiative#66 (closed, not merged): AVE's four-record pilot was hand-appended to generated data/entries/ files with no FRAMEWORK_FILES registration, which the maintainer noted would have been silently deleted by the project's next generator run even if the separate governance question hadn't already closed the PR. Confirmed #66 is closed with no further action pending before writing this. CHANGELOG.md records the section rename and rationale. --- CHANGELOG.md | 16 ++++++++ docs/specs/scaling-and-governance.md | 55 +++++++++++++++++++++++++++- 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 627cd63..236d1ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,22 @@ Format: [Semantic Versioning](https://semver.org). Schema versions and record se ## [Unreleased] ### Changed +- `docs/specs/scaling-and-governance.md` Section 4 is now "Crosswalk + discipline", covering two checks instead of one. The existing numbering + caution becomes 4.1 unchanged; new 4.2 covers submitting content into an + external project's repository. Before proposing content into any + external repo: determine whether the target file is generated or + hand-authored, find the project's own registration mechanism if it is + generated, and run that generator locally against the change before + opening anything. Prompted by + `GenAI-Security-Project/GenAI-Data-Security-Initiative#66` (closed, not + merged), where AVE's four-record pilot was hand-appended to generated + `data/entries/` files with no `FRAMEWORK_FILES` registration; the + project's next generator run would have silently deleted every entry. + The PR closed primarily on a separate governance question, so the defect + was never paid for, which is the reason to write the check down now. + Nothing cited Section 4 externally, so no reference renumbering was + needed. - `scripts/check_confidence_signal.py` now reports two named findings rather than one warning. Running its engine-set cardinality test and the `verification_basis` derivation against each other over the same diff --git a/docs/specs/scaling-and-governance.md b/docs/specs/scaling-and-governance.md index dfdb08a..c950376 100644 --- a/docs/specs/scaling-and-governance.md +++ b/docs/specs/scaling-and-governance.md @@ -86,7 +86,13 @@ separately as part of a future version bump (alongside `owasp_ast`, see by this policy document. This section states the policy the schema change will implement, it does not implement it. -## 4. Crosswalk numbering caution +## 4. Crosswalk discipline + +Two checks that apply to every crosswalk AVE builds or submits. Both are +the same discipline: confirm how the external thing actually behaves, not +how it looks. + +### 4.1 Numbering caution External frameworks still being drafted (OWASP's MCP Top 10 has not been formally ratified as of this writing) get independently @@ -106,6 +112,53 @@ symmetrically: if another project ever crosswalks to AVE's own `owasp_mcp` field by number rather than meaning, the same risk runs the other way. +### 4.2 Submitting content into an external project's repository + +A crosswalk that is correct at the mapping level can still be defective at +the mechanical level, by being written into a file the target project does +not actually hand-author. Before proposing content into any external +project's repository, confirm how that project builds the file being +edited. Three checks, in order, every time: + +1. **Is the target file generated or hand-authored?** Look for a + generator script referencing the target path (`grep -rn + "data/entries\|generate" scripts/`, or that project's equivalent) + before assuming the file can be edited directly. +2. **If it is generated, find the registration mechanism.** A manifest, a + config listing what feeds the generator, a `FRAMEWORK_FILES`-style + registry, whatever that project's own convention is. Register the new + source. Do not append to the generator's output and assume it + persists. +3. **Run the generator locally against the proposed change**, where the + project's tooling allows it. If the entry disappears or is + overwritten, that is the defect, found before submission instead of + after. + +**The precedent this guards against, stated directly.** AVE's four-record +pilot into the GenAI Data Security Initiative +(`GenAI-Security-Project/GenAI-Data-Security-Initiative#66`, closed +2026-09-14, not merged) hand-appended its entries to +`data/entries/ASI02/04/05.json` with no `FRAMEWORK_FILES` registration and +no registry entry. Those files are generated. That project's maintainer +identified it directly in the close: the next run of their own generator +would have silently deleted every AVE entry. The PR closed primarily on a +separate governance question, that AVE does not yet meet that project's +independent-governance bar, so the defect never had to be paid for. It was +still real, and reading the target repo's build before writing into it +would have caught it. + +**A prior submission that did not need this check is not evidence the +check can be skipped.** The OpenCRE pilot (`OWASP/OpenCRE#1017`) and the +OWASP MCP Top 10 finding (`OWASP/www-project-mcp-top-10#52`) went into +hand-authored content and plain issue text, so neither exercised a +generator at all. Every project's real build process is different, and the +only way to know which kind a target is, is to check that target. + +**Resubmission is gated on the governance question, not on this defect.** +Fixing the registration mechanics does not make a closed submission ready +to reopen where it closed on independent governance. That is a separate +question on its own timeline (Section 1, review authority). + ## 5. ID stability policy The pieces of this guarantee already exist scattered across Sections 2