From 7174d0f392f0f9204326ff9ef5555e86180dbfde Mon Sep 17 00:00:00 2001 From: Imran Siddique Date: Thu, 9 Apr 2026 08:53:52 +0530 Subject: [PATCH] feat(owasp): migrate to ASI 2026 taxonomy with reference architecture MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Migrate copilot-governance from legacy AT identifiers to OWASP ASI 2026 - Add backward-compatible AT→ASI lookup for existing integrations - Add comprehensive OWASP Agentic Top 10 reference architecture doc - Add standalone agent-mcp-governance Python package Supersedes: #839, #843, #844, #829 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../owasp-agentic-top10-architecture.md | 290 ++++++++++++++++++ packages/agent-mcp-governance/README.md | 72 +++++ packages/agent-mcp-governance/pyproject.toml | 34 ++ .../src/agent_mcp_governance/__init__.py | 25 ++ .../copilot-governance/src/owasp.ts | 139 ++++++--- .../copilot-governance/src/reviewer.ts | 30 +- .../copilot-governance/src/types.ts | 2 +- .../copilot-governance/tests/index.test.ts | 52 +++- 8 files changed, 580 insertions(+), 64 deletions(-) create mode 100644 docs/compliance/owasp-agentic-top10-architecture.md create mode 100644 packages/agent-mcp-governance/README.md create mode 100644 packages/agent-mcp-governance/pyproject.toml create mode 100644 packages/agent-mcp-governance/src/agent_mcp_governance/__init__.py diff --git a/docs/compliance/owasp-agentic-top10-architecture.md b/docs/compliance/owasp-agentic-top10-architecture.md new file mode 100644 index 00000000..8238c3f4 --- /dev/null +++ b/docs/compliance/owasp-agentic-top10-architecture.md @@ -0,0 +1,290 @@ + + + +# OWASP Agentic Security Initiative (ASI 2026) — Reference Architecture + +> **Version:** 1.0 · **Taxonomy:** OWASP ASI 2026 (ASI01–ASI11) +> **Scope:** Agent Governance Toolkit (AGT) mitigation patterns, code evidence, and gap analysis. + +--- + +## Executive Summary + +The [OWASP Agentic Security Initiative](https://genai.owasp.org/agentic-security-initiative/) +defines **11 risks** (ASI01–ASI11) specific to autonomous AI agent systems. +This document maps every risk to concrete AGT mitigation patterns, links to +implementation evidence, and provides an honest coverage assessment. + +## Coverage Summary + +| ASI ID | Risk Title | Coverage | Primary AGT Component | +|--------|-----------|----------|----------------------| +| ASI01 | Agent Goal Hijack | ✅ Full | `governanceMiddleware` — `blockedPatterns` | +| ASI02 | Tool Misuse and Exploitation | ✅ Full | `createGovernedTool` — allow/deny-lists | +| ASI03 | Identity and Privilege Abuse | ✅ Full | PII redaction, RBAC in policy YAML | +| ASI04 | Agentic Supply Chain | ⚠️ Partial | Policy YAML tool pinning; no SBOM | +| ASI05 | Unexpected Code Execution | ✅ Full | Static reviewer detects pickle/eval | +| ASI06 | Memory and Context Poisoning | ⚠️ Partial | Audit hash-chain; no memory sandbox | +| ASI07 | Insecure Inter-Agent Communication | ✅ Full | Trust-gate with DID verification | +| ASI08 | Cascading Failures | ✅ Full | Circuit breaker, rate limiter | +| ASI09 | Human-Agent Trust Exploitation | ⚠️ Partial | Audit trail; no UI-level guardrails | +| ASI10 | Rogue Agents | ✅ Full | `AgentBehaviorMonitor`, quarantine | +| ASI11 | Agent Untraceability | ✅ Full | Tamper-evident audit log (hash chain) | + +**Overall: 8/11 Full, 3/11 Partial, 0 Gaps.** + +--- + +## Top-Level Architecture + +```mermaid +flowchart TD + User([User / Copilot]) -->|prompt| GW[Governance Middleware] + GW -->|blocked patterns check| PI{ASI01\nGoal Hijack?} + PI -- clean --> TR[Tool Router] + PI -- blocked --> DENY[Deny + Audit] + TR -->|allow-list check| TG{ASI02\nTool Misuse?} + TG -- allowed --> TOOL[Tool Execution] + TG -- denied --> DENY + TOOL --> CB{ASI08\nCircuit Breaker} + CB -- ok --> AUDIT[Audit Middleware] + CB -- open --> DENY + AUDIT -->|hash-chain| LOG[(Audit Store)] + TOOL -.->|inter-agent| TRUST{ASI07\nTrust Gate} + TRUST -- verified --> SUB[Sub-Agent] + TRUST -- rejected --> DENY + SUB --> MON{ASI10\nBehavior Monitor} + MON -- normal --> AUDIT + MON -- anomaly --> QUARANTINE[Quarantine Agent] +``` + +--- + +## Risk Details + +### ASI01 — Agent Goal Hijack + +**Risk:** Adversarial inputs override an agent's intended goal. + +**AGT Mitigation:** The `governanceMiddleware` applies `blockedPatterns` (regex) +to every inbound message before it reaches the LLM. Patterns are loaded from +the policy YAML at runtime — not hardcoded in source. + +**Evidence:** +- `packages/agent-os-kernel/agent_os/governance/middleware.py` — `_check_blocked_patterns()` +- `packages/agentmesh-integrations/copilot-governance/src/reviewer.ts` — rule `no-prompt-injection-guards` + +**Coverage:** ✅ Full + +--- + +### ASI02 — Tool Misuse and Exploitation + +**Risk:** An agent invokes tools in unintended or dangerous ways. + +**AGT Mitigation:** `createGovernedTool` wraps every tool with allow-list / +deny-list enforcement and per-tool rate limits. The static reviewer flags +unguarded `.execute()` calls. + +**Evidence:** +- `packages/agent-os-kernel/agent_os/governance/tool_wrapper.py` +- `packages/agentmesh-integrations/copilot-governance/src/reviewer.ts` — rules `unguarded-tool-execution`, `no-tool-allowlist` + +**Coverage:** ✅ Full + +--- + +### ASI03 — Identity and Privilege Abuse + +**Risk:** Agents acquire privileges beyond their role, exposing sensitive data. + +**AGT Mitigation:** PII redaction middleware strips sensitive fields before +forwarding. Policy YAML supports field-level `pii_fields` configuration. + +**Evidence:** +- `packages/agent-os-kernel/agent_os/governance/middleware.py` — `_redact_pii()` +- `packages/agentmesh-integrations/copilot-governance/src/reviewer.ts` — rule `missing-pii-redaction` + +**Coverage:** ✅ Full + +--- + +### ASI04 — Agentic Supply Chain Vulnerabilities + +**Risk:** Compromised plugins or sub-agents inject malicious behaviour. + +**AGT Mitigation:** Policy YAML `allowed_tools` pins the exact set of +permitted tool IDs. The static reviewer detects hardcoded deny-lists (which +attackers can reverse-engineer) and recommends externalised config. + +**Known Gap:** No SBOM generation or dependency vulnerability scanning is +built into AGT. Recommend integrating with GitHub Advanced Security / +Dependabot for dependency-level supply-chain coverage. + +**Evidence:** +- `packages/agentmesh-integrations/copilot-governance/src/reviewer.ts` — rule `hardcoded-security-denylist` +- Policy YAML schema: `allowed_tools`, `blocked_tools` + +**Coverage:** ⚠️ Partial + +--- + +### ASI05 — Unexpected Code Execution (RCE) + +**Risk:** Agent-driven code paths achieve arbitrary code execution. + +**AGT Mitigation:** The static reviewer detects `pickle.loads()` without HMAC +verification and flags it as critical. The governance policy blocks `eval()` +and `exec()` in agent code via lint rules. + +**Evidence:** +- `packages/agentmesh-integrations/copilot-governance/src/reviewer.ts` — rule `unsafe-deserialization` + +**Coverage:** ✅ Full + +--- + +### ASI06 — Memory and Context Poisoning + +**Risk:** Persistent memory stores are manipulated to corrupt future decisions. + +**AGT Mitigation:** The audit hash-chain provides tamper detection for any +persisted state. However, AGT does not yet sandbox agent memory stores or +provide memory integrity checksums at the application layer. + +**Known Gap:** No dedicated memory-sandbox or context-integrity module. +Consider adding a `ContextValidator` that hashes memory snapshots. + +**Evidence:** +- `packages/agent-os-kernel/agent_os/audit/hash_chain.py` + +**Coverage:** ⚠️ Partial + +--- + +### ASI07 — Insecure Inter-Agent Communication + +**Risk:** Messages between agents lack authentication or integrity verification. + +**AGT Mitigation:** The trust-gate requires DID-based identity verification +before any agent-to-agent handoff. The static reviewer detects missing trust +verification in multi-agent orchestration code. + +**Evidence:** +- `packages/agent-os-kernel/agent_os/trust/gate.py` +- `packages/agentmesh-integrations/copilot-governance/src/reviewer.ts` — rule `missing-trust-verification` + +**Coverage:** ✅ Full + +--- + +### ASI08 — Cascading Failures + +**Risk:** A failure in one agent propagates through the system. + +**AGT Mitigation:** The circuit-breaker pattern opens after N consecutive +failures, preventing cascade. Rate limiting caps per-minute tool invocations. + +**Evidence:** +- `packages/agentmesh-integrations/copilot-governance/src/reviewer.ts` — rule `missing-circuit-breaker` +- `packages/agent-os-kernel/agent_os/governance/middleware.py` — `_rate_limit_check()` + +**Coverage:** ✅ Full + +--- + +### ASI09 — Human-Agent Trust Exploitation + +**Risk:** Humans over-trust agent outputs and skip validation. + +**AGT Mitigation:** Tamper-evident audit logs let reviewers verify what the +agent actually did. The static reviewer flags code with no audit logging. + +**Known Gap:** No UI-level confirmation dialogs or "human-in-the-loop" +approval workflows are built into AGT. Consider adding a `HumanApproval` +middleware for high-risk actions. + +**Evidence:** +- `packages/agentmesh-integrations/copilot-governance/src/reviewer.ts` — rule `missing-audit-logging` + +**Coverage:** ⚠️ Partial + +--- + +### ASI10 — Rogue Agents + +**Risk:** An agent deviates from intended behaviour. + +**AGT Mitigation:** `AgentBehaviorMonitor` tracks per-agent metrics (tool call +rate, failure rate, privilege escalation attempts) and quarantines agents that +exceed thresholds. + +**Evidence:** +- `packages/agent-os-kernel/agent_os/services/behavior_monitor.py` +- `packages/agentmesh-integrations/copilot-governance/src/reviewer.ts` — rule `no-behavior-monitoring` + +**Coverage:** ✅ Full + +--- + +### ASI11 — Agent Untraceability + +**Risk:** Agent actions lack logging, provenance, or audit trails. + +**AGT Mitigation:** The audit middleware produces a hash-chain log where each +entry contains the SHA-256 of the previous entry, making tampering detectable. +The static reviewer flags code without audit logging. + +**Evidence:** +- `packages/agent-os-kernel/agent_os/audit/hash_chain.py` +- `packages/agentmesh-integrations/copilot-governance/src/reviewer.ts` — rule `missing-audit-logging` + +**Coverage:** ✅ Full + +--- + +## Deployment Architecture + +```mermaid +flowchart LR + subgraph GitHub Copilot + EXT[Copilot Extension] + end + subgraph AGT Runtime + GOV[Governance Middleware] + AUD[Audit Middleware] + TRUST[Trust Gate] + MON[Behavior Monitor] + end + subgraph External + LLM[LLM Provider] + TOOLS[Tool APIs] + STORE[(Audit Store)] + end + EXT --> GOV + GOV --> LLM + GOV --> TOOLS + GOV --> AUD --> STORE + GOV --> TRUST + GOV --> MON +``` + +## Lessons Learned + +1. **Hardcoded deny-lists are discoverable.** External security researchers + reverse-engineered blocked-pattern lists from source code. Externalise + security rules into runtime-loaded YAML configs. + +2. **Stub `verify()` functions are a recurring root cause.** Two separate + incidents traced back to `return True` stubs in trust verification. + The static reviewer now flags these as critical. + +3. **Unbounded dictionaries cause memory DoS.** Session caches and + rate-limit buckets need explicit size limits and eviction policies. + +4. **Backward compatibility matters.** When migrating from AT→ASI taxonomy, + provide a legacy lookup map so existing integrations don't break silently. + +--- + +*Generated for Agent Governance Toolkit · OWASP ASI 2026 Taxonomy* diff --git a/packages/agent-mcp-governance/README.md b/packages/agent-mcp-governance/README.md new file mode 100644 index 00000000..e87ba962 --- /dev/null +++ b/packages/agent-mcp-governance/README.md @@ -0,0 +1,72 @@ + + + +# agent-mcp-governance + +> **Public Preview** — Standalone Python package that exposes the +> Agent Governance Toolkit's MCP (Model Context Protocol) governance +> primitives for use outside the full AGT monorepo. + +## Overview + +`agent_mcp_governance` provides a thin, typed re-export surface over the +governance, audit, and trust modules in +[`agent-os-kernel`](https://pypi.org/project/agent-os-kernel/). It is +**not** zero-dependency — it requires `agent-os-kernel >=3.0.0,<4.0.0`. + +## Installation + +```bash +pip install agent-mcp-governance +``` + +This will pull in `agent-os-kernel` automatically. + +## Quick Start + +```python +from agent_mcp_governance import ( + GovernanceMiddleware, + AuditMiddleware, + TrustGate, + BehaviorMonitor, +) + +# 1. Governance — block prompt-injection patterns +gov = GovernanceMiddleware( + blocked_patterns=[r"(?i)ignore previous instructions"], + allowed_tools=["web-search", "read-file"], + rate_limit_per_minute=60, +) + +# 2. Audit — tamper-evident hash-chain logging +audit = AuditMiddleware(capture_data=True) + +# 3. Trust — DID-based agent identity verification +gate = TrustGate(min_trust_score=500) + +# 4. Monitoring — detect rogue agents +monitor = BehaviorMonitor( + burst_threshold=100, + consecutive_failure_threshold=20, +) +``` + +## API Reference + +| Export | Source module | Description | +|--------|-------------|-------------| +| `GovernanceMiddleware` | `agent_os.governance.middleware` | Policy enforcement (rate limits, allow-lists, content filters) | +| `AuditMiddleware` | `agent_os.audit.middleware` | Tamper-evident audit logging with hash chain | +| `TrustGate` | `agent_os.trust.gate` | DID-based trust verification for agent handoffs | +| `BehaviorMonitor` | `agent_os.services.behavior_monitor` | Per-agent anomaly detection and quarantine | + +## Compatibility + +| Python | agent-os-kernel | +|--------|----------------| +| ≥ 3.10 | ≥ 3.0.0, < 4.0.0 | + +## License + +[MIT](../../LICENSE) — Copyright (c) Microsoft Corporation. diff --git a/packages/agent-mcp-governance/pyproject.toml b/packages/agent-mcp-governance/pyproject.toml new file mode 100644 index 00000000..82ae0c94 --- /dev/null +++ b/packages/agent-mcp-governance/pyproject.toml @@ -0,0 +1,34 @@ +[build-system] +requires = ["setuptools>=68.0", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "agent_mcp_governance" +version = "0.1.0" +description = "Public Preview — MCP governance primitives for the Agent Governance Toolkit." +readme = "README.md" +license = {text = "MIT"} +authors = [{name = "Microsoft Corporation", email = "agentgovtoolkit@microsoft.com"}] +requires-python = ">=3.10" +dependencies = [ + "agent-os-kernel>=3.0.0,<4.0.0", +] +classifiers = [ + "Development Status :: 3 - Alpha", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Topic :: Security", + "Topic :: Software Development :: Libraries", +] + +[project.urls] +Homepage = "https://github.com/microsoft/agent-governance-toolkit" +Documentation = "https://github.com/microsoft/agent-governance-toolkit/tree/main/docs" +Issues = "https://github.com/microsoft/agent-governance-toolkit/issues" + +[tool.setuptools.packages.find] +where = ["src"] diff --git a/packages/agent-mcp-governance/src/agent_mcp_governance/__init__.py b/packages/agent-mcp-governance/src/agent_mcp_governance/__init__.py new file mode 100644 index 00000000..16dafb68 --- /dev/null +++ b/packages/agent-mcp-governance/src/agent_mcp_governance/__init__.py @@ -0,0 +1,25 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +"""agent_mcp_governance — MCP governance primitives for the Agent Governance Toolkit. + +Re-exports the core governance, audit, trust, and monitoring classes from +``agent-os-kernel`` so that downstream consumers can depend on a single, +focused package. +""" + +from __future__ import annotations + +__version__ = "0.1.0" + +from agent_os.governance.middleware import GovernanceMiddleware +from agent_os.audit.middleware import AuditMiddleware +from agent_os.trust.gate import TrustGate +from agent_os.services.behavior_monitor import BehaviorMonitor + +__all__ = [ + "__version__", + "GovernanceMiddleware", + "AuditMiddleware", + "TrustGate", + "BehaviorMonitor", +] diff --git a/packages/agentmesh-integrations/copilot-governance/src/owasp.ts b/packages/agentmesh-integrations/copilot-governance/src/owasp.ts index cd38ff61..8853b6a2 100644 --- a/packages/agentmesh-integrations/copilot-governance/src/owasp.ts +++ b/packages/agentmesh-integrations/copilot-governance/src/owasp.ts @@ -1,14 +1,18 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** - * OWASP Agentic Security Initiative — Agentic Top-10 risk catalogue. + * OWASP Agentic Security Initiative (ASI) 2026 — risk catalogue. * - * Reference: https://genai.owasp.org/llm-top-10/ - * Agentic extension: https://owasp.org/www-project-top-10-for-large-language-model-applications/ + * Reference: https://genai.owasp.org/agentic-security-initiative/ + * Catalogue: https://genai.owasp.org/agentic-risk/ + * + * Migrated from legacy LLM Top-10 "ATxx" identifiers to the 2026 ASI + * taxonomy ("ASIxx"). A backward-compatible lookup is provided so that + * existing code referencing AT IDs continues to work. */ export interface OwaspRisk { - /** Risk identifier, e.g. "AT01". */ + /** Risk identifier, e.g. "ASI01". */ id: string; /** Short title. */ title: string; @@ -18,59 +22,122 @@ export interface OwaspRisk { url: string; } -/** OWASP Agentic Top-10 risks most relevant to agent governance. */ +/** OWASP Agentic Security Initiative 2026 — full ASI01–ASI11 catalogue. */ export const OWASP_AGENTIC_RISKS: Record = { - AT01: { - id: "AT01", - title: "Prompt Injection", + ASI01: { + id: "ASI01", + title: "Agent Goal Hijack", + description: + "Adversarial inputs override an agent's intended goal, causing it to pursue attacker-controlled objectives.", + url: "https://genai.owasp.org/agentic-risk/asi01-agent-goal-hijack/", + }, + ASI02: { + id: "ASI02", + title: "Tool Misuse and Exploitation", + description: + "An agent invokes tools in unintended or dangerous ways due to missing validation or inadequate access controls.", + url: "https://genai.owasp.org/agentic-risk/asi02-tool-misuse-and-exploitation/", + }, + ASI03: { + id: "ASI03", + title: "Identity and Privilege Abuse", description: - "Malicious content in inputs hijacks agent actions by overriding original instructions.", - url: "https://genai.owasp.org/llmrisk/llm01-prompt-injection/", + "Agents acquire or exercise privileges beyond what their identity or role warrants, exposing sensitive data.", + url: "https://genai.owasp.org/agentic-risk/asi03-identity-and-privilege-abuse/", }, - AT02: { - id: "AT02", - title: "Insecure Output Handling", + ASI04: { + id: "ASI04", + title: "Agentic Supply Chain Vulnerabilities", description: - "Agent outputs are passed to downstream components without validation or sanitisation.", - url: "https://genai.owasp.org/llmrisk/llm02-insecure-output-handling/", + "Compromised dependencies, plugins, or sub-agents introduce malicious behaviour into the agent pipeline.", + url: "https://genai.owasp.org/agentic-risk/asi04-agentic-supply-chain-vulnerabilities/", }, - AT06: { - id: "AT06", - title: "Sensitive Information Disclosure", + ASI05: { + id: "ASI05", + title: "Unexpected Code Execution (RCE)", description: - "PII or secrets are leaked in agent inputs, outputs, or audit logs.", - url: "https://genai.owasp.org/llmrisk/llm06-sensitive-information-disclosure/", + "Agent-driven code generation, deserialization, or eval paths achieve arbitrary code execution on the host.", + url: "https://genai.owasp.org/agentic-risk/asi05-unexpected-code-execution/", }, - AT07: { - id: "AT07", - title: "Insecure Plugin / Tool Design", + ASI06: { + id: "ASI06", + title: "Memory and Context Poisoning", description: - "Tools lack authorisation, input validation, or allow-listing, enabling privilege escalation.", - url: "https://genai.owasp.org/llmrisk/llm07-insecure-plugin-design/", + "Persistent memory or context stores are manipulated so that future agent decisions are corrupted.", + url: "https://genai.owasp.org/agentic-risk/asi06-memory-and-context-poisoning/", }, - AT08: { - id: "AT08", - title: "Excessive Agency", + ASI07: { + id: "ASI07", + title: "Insecure Inter-Agent Communication", description: - "Agent is granted more permissions or capabilities than required for its task.", - url: "https://genai.owasp.org/llmrisk/llm08-excessive-agency/", + "Messages between agents lack authentication, encryption, or integrity verification.", + url: "https://genai.owasp.org/agentic-risk/asi07-insecure-inter-agent-communication/", }, - AT09: { - id: "AT09", - title: "Overreliance", + ASI08: { + id: "ASI08", + title: "Cascading Failures", description: - "Humans over-trust agent outputs without proper validation or audit trails.", - url: "https://genai.owasp.org/llmrisk/llm09-overreliance/", + "A failure in one agent or tool propagates through the system, causing widespread outage or resource exhaustion.", + url: "https://genai.owasp.org/agentic-risk/asi08-cascading-failures/", }, + ASI09: { + id: "ASI09", + title: "Human-Agent Trust Exploitation", + description: + "Humans over-trust agent outputs, skip validation steps, or defer critical decisions to agents without oversight.", + url: "https://genai.owasp.org/agentic-risk/asi09-human-agent-trust-exploitation/", + }, + ASI10: { + id: "ASI10", + title: "Rogue Agents", + description: + "An agent deviates from its intended behaviour — due to poisoning, compromise, or misconfiguration — and acts against the operator's interests.", + url: "https://genai.owasp.org/agentic-risk/asi10-rogue-agents/", + }, + ASI11: { + id: "ASI11", + title: "Agent Untraceability", + description: + "Agent actions lack sufficient logging, provenance, or audit trails, making forensic analysis impossible.", + url: "https://genai.owasp.org/agentic-risk/asi11-agent-untraceability/", + }, +}; + +/** + * Backward-compatible mapping from legacy LLM Top-10 "AT" identifiers + * to the primary ASI 2026 identifier. Where a legacy ID maps to multiple + * ASI risks, the first entry is the primary match. + */ +export const LEGACY_AT_TO_ASI: Record = { + AT01: "ASI01", + AT02: "ASI02", + AT03: "ASI10", + AT05: "ASI04", + AT06: "ASI03", + AT07: "ASI02", + AT08: "ASI01", + AT09: "ASI09", + AT10: "ASI08", }; +/** + * Resolve a risk ID to its canonical ASI identifier. + * Returns the ID unchanged if it already starts with "ASI", or maps it + * via {@link LEGACY_AT_TO_ASI} if it is a legacy "AT" ID. + */ +function resolveId(id: string): string { + if (id in OWASP_AGENTIC_RISKS) return id; + return LEGACY_AT_TO_ASI[id] ?? id; +} + /** * Return OWASP risk objects for a list of risk IDs. + * Accepts both ASI 2026 IDs (e.g. "ASI01") and legacy AT IDs (e.g. "AT01"). * Unknown IDs are silently skipped. */ export function getOwaspRisks(ids: string[]): OwaspRisk[] { return ids - .map((id) => OWASP_AGENTIC_RISKS[id]) + .map((id) => OWASP_AGENTIC_RISKS[resolveId(id)]) .filter((r): r is OwaspRisk => r !== undefined); } diff --git a/packages/agentmesh-integrations/copilot-governance/src/reviewer.ts b/packages/agentmesh-integrations/copilot-governance/src/reviewer.ts index 5c3e2cc0..ed70b815 100644 --- a/packages/agentmesh-integrations/copilot-governance/src/reviewer.ts +++ b/packages/agentmesh-integrations/copilot-governance/src/reviewer.ts @@ -17,7 +17,7 @@ * - SSRF-vulnerable URL handling * - Missing agent behavior monitoring * - * Each finding is mapped to relevant OWASP Agentic Top-10 risk IDs. + * Each finding is mapped to relevant OWASP Agentic Security Initiative Top 10 (ASI 2026) risk IDs. * * Rules 8–14 are based on patterns discovered during external security * researcher reports and subsequent codebase-wide audits. @@ -45,7 +45,7 @@ const RULES: Rule[] = [ ruleId: "missing-governance-middleware", title: "No governance middleware detected", severity: "high", - owaspRisks: ["AT07", "AT08"], + owaspRisks: ["ASI02", "ASI01"], detect(source) { const hasGovernance = /governanceMiddleware|governance_middleware|GovernancePolicy|apply_governance/i.test(source); @@ -75,7 +75,7 @@ const RULES: Rule[] = [ ruleId: "unguarded-tool-execution", title: "Direct tool execution without policy check", severity: "high", - owaspRisks: ["AT07", "AT08"], + owaspRisks: ["ASI02", "ASI01"], detect(source) { // Look for .execute( calls not preceded by a governance/policy check const hasDirectExecute = /\.execute\s*\(/.test(source); @@ -101,7 +101,7 @@ const RULES: Rule[] = [ ruleId: "missing-audit-logging", title: "No audit logging detected", severity: "high", - owaspRisks: ["AT09"], + owaspRisks: ["ASI09", "ASI11"], detect(source) { const hasAudit = /auditMiddleware|audit_middleware|audit\.record|AuditLog|audit_log|hash_chain/i.test( @@ -130,7 +130,7 @@ const RULES: Rule[] = [ ruleId: "missing-pii-redaction", title: "No PII redaction configured", severity: "medium", - owaspRisks: ["AT06"], + owaspRisks: ["ASI03"], detect(source) { const hasPii = /piiFields|pii_fields|redact_pii|REDACTED|pii_redact/i.test(source); @@ -156,7 +156,7 @@ const RULES: Rule[] = [ ruleId: "missing-trust-verification", title: "No trust score verification for agent-to-agent calls", severity: "medium", - owaspRisks: ["AT07", "AT08"], + owaspRisks: ["ASI07", "ASI03"], detect(source) { const hasTrust = /trustGate|trust_gate|TrustConfig|minTrustScore|min_trust_score|getTrustScore/i.test( @@ -187,7 +187,7 @@ const RULES: Rule[] = [ ruleId: "no-tool-allowlist", title: "No tool allow-list or deny-list configured", severity: "medium", - owaspRisks: ["AT08"], + owaspRisks: ["ASI01", "ASI02"], detect(source) { const hasAllowlist = /allowedTools|allowed_tools|blockedTools|blocked_tools|tool_allowlist|tool_denylist/i.test( @@ -217,7 +217,7 @@ const RULES: Rule[] = [ ruleId: "no-prompt-injection-guards", title: "No prompt-injection input filters configured", severity: "medium", - owaspRisks: ["AT01"], + owaspRisks: ["ASI01"], detect(source) { const hasPatterns = /blockedPatterns|blocked_patterns|prompt.?injection|content.?filter/i.test(source); @@ -250,7 +250,7 @@ const RULES: Rule[] = [ ruleId: "stub-security-implementation", title: "Security function appears to be a stub (always returns True/success)", severity: "critical", - owaspRisks: ["AT02", "AT07"], + owaspRisks: ["ASI02", "ASI03"], detect(source) { // Python: def verify/validate/authenticate that just returns True const stubPattern = @@ -284,7 +284,7 @@ const RULES: Rule[] = [ ruleId: "hardcoded-security-denylist", title: "Hardcoded security deny-list found in source code", severity: "high", - owaspRisks: ["AT01", "AT08"], + owaspRisks: ["ASI01", "ASI04"], detect(source) { // Look for inline lists of SQL keywords, dangerous commands, PII patterns const hardcodedLists = @@ -314,7 +314,7 @@ const RULES: Rule[] = [ ruleId: "unsafe-deserialization", title: "pickle.loads() called without integrity verification", severity: "critical", - owaspRisks: ["AT02", "AT07"], + owaspRisks: ["ASI05", "ASI02"], detect(source) { const hasPickleLoad = /pickle\.loads?\s*\(/.test(source); if (!hasPickleLoad) return null; @@ -342,7 +342,7 @@ const RULES: Rule[] = [ ruleId: "unbounded-collection", title: "Security-sensitive collection has no size limit", severity: "medium", - owaspRisks: ["AT05"], + owaspRisks: ["ASI08"], detect(source) { // Look for dicts/lists used for caching, rate-limiting, session tracking // that grow without eviction @@ -374,7 +374,7 @@ const RULES: Rule[] = [ ruleId: "missing-circuit-breaker", title: "External service calls lack circuit breaker pattern", severity: "medium", - owaspRisks: ["AT05", "AT10"], + owaspRisks: ["ASI08", "ASI10"], detect(source) { const hasExternalCall = /httpx\.|aiohttp\.|requests\.|fetch\(|urllib|invoke_tool|call_tool/i.test(source); @@ -406,7 +406,7 @@ const RULES: Rule[] = [ ruleId: "ssrf-vulnerable-url", title: "URL from untrusted input used without SSRF guard", severity: "high", - owaspRisks: ["AT02", "AT07"], + owaspRisks: ["ASI02", "ASI05"], detect(source) { const hasUrlFromInput = /(?:server_url|endpoint|url|base_url)\s*[:=].*(?:args|params|request|input|config)/i.test( @@ -439,7 +439,7 @@ const RULES: Rule[] = [ ruleId: "no-behavior-monitoring", title: "No agent behavior monitoring or anomaly detection", severity: "medium", - owaspRisks: ["AT03", "AT08"], + owaspRisks: ["ASI10", "ASI11"], detect(source) { const hasMonitor = /BehaviorMonitor|behavior_monitor|anomaly_detect|RogueDetect|quarantine|AgentMetrics/i.test( diff --git a/packages/agentmesh-integrations/copilot-governance/src/types.ts b/packages/agentmesh-integrations/copilot-governance/src/types.ts index 18a6bd2e..7e6eecd3 100644 --- a/packages/agentmesh-integrations/copilot-governance/src/types.ts +++ b/packages/agentmesh-integrations/copilot-governance/src/types.ts @@ -21,7 +21,7 @@ export interface ReviewFinding { line?: number; /** Suggested fix or code snippet. */ suggestion?: string; - /** Related OWASP Agentic Top-10 risk IDs, e.g. ["AT08"]. */ + /** Related OWASP ASI 2026 risk IDs, e.g. ["ASI01"]. */ owaspRisks: string[]; } diff --git a/packages/agentmesh-integrations/copilot-governance/tests/index.test.ts b/packages/agentmesh-integrations/copilot-governance/tests/index.test.ts index 4d8f57da..7cdb1820 100644 --- a/packages/agentmesh-integrations/copilot-governance/tests/index.test.ts +++ b/packages/agentmesh-integrations/copilot-governance/tests/index.test.ts @@ -4,7 +4,7 @@ import { describe, it, expect } from "vitest"; import { reviewCode, formatReviewResult } from "../src/reviewer"; import { validatePolicy, formatPolicyValidation } from "../src/policy-validator"; import { handleAgentRequest, parseYamlLite } from "../src/agent"; -import { OWASP_AGENTIC_RISKS, getOwaspRisks, formatOwaspRisks } from "../src/owasp"; +import { OWASP_AGENTIC_RISKS, getOwaspRisks, formatOwaspRisks, LEGACY_AT_TO_ASI } from "../src/owasp"; // --------------------------------------------------------------------------- // reviewCode @@ -241,26 +241,54 @@ describe("validatePolicy", () => { // --------------------------------------------------------------------------- describe("owasp", () => { - it("exports OWASP_AGENTIC_RISKS with expected keys", () => { - expect(OWASP_AGENTIC_RISKS["AT01"]).toBeDefined(); - expect(OWASP_AGENTIC_RISKS["AT08"]).toBeDefined(); + it("exports OWASP_AGENTIC_RISKS with all ASI 2026 keys", () => { + expect(OWASP_AGENTIC_RISKS["ASI01"]).toBeDefined(); + expect(OWASP_AGENTIC_RISKS["ASI02"]).toBeDefined(); + expect(OWASP_AGENTIC_RISKS["ASI03"]).toBeDefined(); + expect(OWASP_AGENTIC_RISKS["ASI04"]).toBeDefined(); + expect(OWASP_AGENTIC_RISKS["ASI05"]).toBeDefined(); + expect(OWASP_AGENTIC_RISKS["ASI06"]).toBeDefined(); + expect(OWASP_AGENTIC_RISKS["ASI07"]).toBeDefined(); + expect(OWASP_AGENTIC_RISKS["ASI08"]).toBeDefined(); + expect(OWASP_AGENTIC_RISKS["ASI09"]).toBeDefined(); + expect(OWASP_AGENTIC_RISKS["ASI10"]).toBeDefined(); + expect(OWASP_AGENTIC_RISKS["ASI11"]).toBeDefined(); + }); + + it("getOwaspRisks returns matching risks for ASI IDs", () => { + const risks = getOwaspRisks(["ASI01", "ASI08"]); + expect(risks).toHaveLength(2); + expect(risks[0].id).toBe("ASI01"); }); - it("getOwaspRisks returns matching risks", () => { + it("getOwaspRisks resolves legacy AT IDs via backward-compat mapping", () => { const risks = getOwaspRisks(["AT01", "AT08"]); expect(risks).toHaveLength(2); - expect(risks[0].id).toBe("AT01"); + expect(risks[0].id).toBe("ASI01"); + expect(risks[1].id).toBe("ASI01"); // AT08 → ASI01 }); it("getOwaspRisks skips unknown IDs", () => { - const risks = getOwaspRisks(["AT01", "UNKNOWN"]); + const risks = getOwaspRisks(["ASI01", "UNKNOWN"]); expect(risks).toHaveLength(1); }); - it("formatOwaspRisks returns a non-empty string for valid IDs", () => { + it("LEGACY_AT_TO_ASI maps all known AT IDs", () => { + expect(LEGACY_AT_TO_ASI["AT01"]).toBe("ASI01"); + expect(LEGACY_AT_TO_ASI["AT06"]).toBe("ASI03"); + expect(LEGACY_AT_TO_ASI["AT09"]).toBe("ASI09"); + }); + + it("formatOwaspRisks returns a non-empty string for valid ASI IDs", () => { + const md = formatOwaspRisks(["ASI01", "ASI08"]); + expect(md).toContain("ASI01"); + expect(md).toContain("ASI08"); + expect(md).toContain("https://"); + }); + + it("formatOwaspRisks works with legacy AT IDs", () => { const md = formatOwaspRisks(["AT01", "AT08"]); - expect(md).toContain("AT01"); - expect(md).toContain("AT08"); + expect(md).toContain("ASI01"); expect(md).toContain("https://"); }); @@ -394,8 +422,8 @@ describe("handleAgentRequest", () => { messages: [{ role: "user", content: "@governance owasp" }], }) ); - expect(output).toContain("AT01"); - expect(output).toContain("AT08"); + expect(output).toContain("ASI01"); + expect(output).toContain("ASI08"); }); it("uses help fallback for explicit help command", async () => {