Every row on this page is a check that drives the real engine, proxy call path, tool-integrity scanner, redaction, audit chain, approvals, rate limiter and metrics against a bundled policy with one rule per mechanism. Nothing in the decision path is mocked. Generated by aggrete conformance from aggrete 0.10.0 on 2026-09-18.
pip install aggrete && aggrete conformance1 not applicable, 0 failing, of 10 controls.
2 not applicable, 0 failing, of 10 controls.
0 not applicable, 0 failing, of 14 controls.
0 not applicable, 0 failing, of 18 controls.
Each prints the evidence it found. --format json exits non-zero on any failure, so this runs in CI; --format md is what an auditor gets.
| check | what it proves | result | evidence |
|---|---|---|---|
| C01 | Refuses before fetching: a walled domain is never contacted | pass | plan__read refused at stage=pre, upstream calls=0, audit rule=CONF-WALL |
| C02 | Catches the combination: three individually-fine reads, the third refused | pass | finance + hr allowed; ops refused pre-fetch by CONF-JOIN with entity overlap |
| C03 | Prompt-injection shield: no write after reading untrusted content | pass | write allowed before taint; after an untrusted read both the write and the private-repo read are refused (CONF-FLOW) |
| C04 | Argument-level rules: the same tool is fine or forbidden by what it is asked | pass | crm__export scope=team allowed; scope=all refused pre-fetch (CONF-ARG) |
| C05 | Redaction: SSNs and emails masked before the model sees the result | pass | result masked; audit redacted={'email': 2, 'ssn': 1} |
| C06 | Inbound secrets: a credential in tool arguments is never forwarded | pass | AWS key in arguments refused, upstream not called, audit rule=inbound-secret |
| C07 | Tool integrity: poisoned descriptions blocked, rug pulls flagged | pass | hidden instruction -> block; definition changed after pin -> alert (rug pull) |
| C08 | Rate limit: per-user ceiling, refused with an audit row | pass | 6th call in the window refused, audit rule=rate-limit |
| C09 | Audit chain: every decision hash-chained; tampering is detected at the line | pass | 3 rows chained and intact; editing line 2 is reported as the first bad line |
| C10 | Identity from the token; HTTP refuses to start without auth; caller tokens never go upstream | pass | email claim -> identity; streamable-http without auth: SystemExit; upstream headers come from config, not the caller |
| C11 | Human-in-the-loop: a held call, an approval, a retry that succeeds, all audited | pass | held (request 6192934eac), approved by the clause owner, retry allowed with purpose on the audit row |
| C12 | Hidden tools: what a person can never call is never listed | pass | walled and blocked domains hidden for non-allowed users; approval-gated tools remain visible |
| C13 | Post-call rules: small groups, self-comparison and budgets refuse the result | pass | results describing 2 people, self+colleague, and 6 distinct customers all refused post-call |
| C14 | Purpose binding: a granted purpose opens a scoped, audited window | pass | refused, then allowed under a granted purpose that is stamped on the audit row |
| C15 | Dry run: 'would this be allowed?' answered without fetching | pass | three-step plan reported REFUSED at step 3 by CONF-JOIN; upstream calls=0 |
| C16 | Observability: metrics and OTLP records derive from the same audit rows | pass | Prometheus counters and an OTLP log record produced from the audit rows |
Source: https://owasp.org/www-project-mcp-top-10/
| control | title | status | shown by | note |
|---|---|---|---|---|
| MCP01 | Token Mismanagement & Secret Exposure | pass | C06, C05, C10 | the proxy holds upstream credentials; callers' tokens are never forwarded (C10) |
| MCP02 | Privilege Escalation via Scope Creep | pass | C01, C12, C04 | |
| MCP03 | Tool Poisoning | pass | C07 | |
| MCP04 | Software Supply Chain Attacks & Dependency Tampering | partial | C07 | rug-pull detection by fingerprint; package-level supply chain is out of scope |
| MCP05 | Command Injection & Execution | partial | C04, C06 | argument-level rules and secret blocking constrain what reaches a server; injection inside the server is the server's job |
| MCP06 | Prompt Injection via Contextual Payloads | pass | C03, C07 | |
| MCP07 | Insufficient Authentication & Authorization | pass | C10, C01, C12 | |
| MCP08 | Lack of Audit and Telemetry | pass | C09, C16 | |
| MCP09 | Shadow MCP Servers | n/a | deployment property: make the proxy the only allowed server (docs/DEPLOY.md, managed client allow-lists) | |
| MCP10 | Context Injection & Over-Sharing | pass | C02, C13, C05 |
Source: https://genai.owasp.org/resource/owasp-top-10-for-agentic-applications-for-2026/
| control | title | status | shown by | note |
|---|---|---|---|---|
| ASI01 | Agent Goal Hijack | pass | C03, C07 | |
| ASI02 | Tool Misuse & Exploitation | pass | C04, C08, C15 | |
| ASI03 | Identity & Privilege Abuse | pass | C10, C01, C12 | |
| ASI04 | Agentic Supply Chain Vulnerabilities | partial | C07 | |
| ASI05 | Unexpected Code Execution | n/a | not a proxy concern; see MCP05 | |
| ASI06 | Memory & Context Poisoning | pass | C03, C05 | |
| ASI07 | Insecure Inter-Agent Communication | n/a | A2A is out of scope for an MCP proxy | |
| ASI08 | Cascading Failures | partial | C08, C16 | |
| ASI09 | Human-Agent Trust Exploitation | pass | C11, C15 | |
| ASI10 | Rogue Agents | pass | C02, C13, C08 |
| control | title | status | shown by | note |
|---|---|---|---|---|
| T2 | Tool Poisoning | pass | C07 | |
| T3 | Full Schema Poisoning | pass | C07 | |
| T4 | Resource Content Poisoning | pass | C03 | |
| T8 | Confused Deputy (OAuth proxy) | pass | C10 | |
| T9 | Insecure Human-in-the-Loop | pass | C11 | |
| T11 | Prompt Injection | pass | C03 | |
| T13 | Consent / User-Approval Fatigue | partial | C11, C15 | approvals are per rule with a TTL, not per call |
| T14 | Resource Exhaustion & Denial of Wallet | pass | C08 | |
| T15 | Invisible Agent Activity | pass | C09, C16 | |
| T16 | Credential / Token Theft | pass | C06, C10 | |
| T20 | Excessive Permissions / Overexposure | pass | C01, C12, C13 | |
| T23 | Insufficient Integrity Checks | pass | C07, C09 | |
| T24 | Data Exfiltration & Corruption | pass | C03, C02, C05 | |
| T34 | Lack of Observability | pass | C16, C09 |
Source: https://standard.aiuc-1.com/
| control | title | status | shown by | note |
|---|---|---|---|---|
| A003.1 | Data access scoping | pass | C01, C02, C13 | |
| A003.2 | Agent identity management | pass | C10 | |
| A003.3 | Agent access & permissions management | partial | C11, C12 | time-limited approvals; per-tool OAuth scopes are on the roadmap |
| A008.1 | Secrets detection in user inputs | pass | C06 | |
| A008.5 | Secrets redaction in logs & artifacts | pass | C05 | |
| B006.1 | Agent service access restrictions | pass | C07, C12 | |
| B006.2 | Agent security monitoring & alerting | pass | C09, C16 | |
| B006.3 | Execution-level safeguards | partial | C07, C01 | |
| B008.1 | API & agentic interface authentication | pass | C10 | |
| B008.3 | Agentic interface data integrity | pass | C07, C06 | |
| C007 | Flag high risk outputs for human review | pass | C11 | |
| D003.1 | Tool authorization & validation | pass | C01, C04 | |
| D003.2 | Rate limits for tools | pass | C08 | |
| D003.3 | Tool call log | pass | C09 | |
| D003.4 | Human-approval workflows | pass | C11 | |
| E009.1 | Third-party access monitoring | pass | C09, C16 | |
| E015.2 | AI agent logging implementation | pass | C09 | |
| E015.4 | Log integrity protection | pass | C09 |
The same scenarios also run from the outside, over real MCP, against any endpoint. Nothing in the suite knows how a gateway words a refusal: every fixture payload carries a unique marker, and a scenario passes when the forbidden marker never reaches the client. Each has a control step, so a target that simply blocks everything scores inconclusive, not pass.
# 1. front this fixture connector with the gateway under test python -m aggrete._mockco --profile fixture # 2. run the scenarios against the gateway aggrete conformance --url https://gateway.example/mcp --token "$TOKEN" aggrete conformance --stdio "my-gateway --config gw.yaml" aggrete conformance --self # Aggrete itself, as the reference aggrete conformance --write-fixture ./fx # the reference config and policy
Two real runs, side by side: Aggrete in front of the fixture, and the fixture with nothing in front of it. The second column is the suite's own sanity check, and what an ungoverned MCP setup looks like.
| scenario | what it tests | aggrete | nothing in front | what happened with nothing in front |
|---|---|---|---|---|
| B00 | Fixture tools are reachable through the target | pass | pass | 9 tools listed |
| B01 | Combination: budget + personnel + rota about the same people | pass | fail | all three reads returned: the combination formed |
| B02 | Exfiltration: no write after reading untrusted content | pass | fail | the write went through after an untrusted read |
| B03 | Arguments: the same tool allowed or refused by what it is asked | pass | fail | scope=all returned the whole base |
| B04 | Redaction: an SSN in a result never reaches the client | pass | fail | the SSN arrived in clear |
| B05 | Inbound secrets: a credential in arguments never reaches the upstream | pass | fail | the upstream received and echoed the key |
| B06 | Tool poisoning: a tool with hidden instructions is not usable | pass | fail | the poisoned tool ran |
| B07 | Walls: a tool this person may never call is hidden or refused | pass | fail | the walled document was returned |
| B08 | Refusals explain themselves (rule and reason, not a bare error) | pass | info | 0 of 0 refusals carried a readable reason |
Controls the outside cannot see (audit integrity, identity handling, approvals) are reported as "not observable" rather than guessed. Those are covered by the sixteen in-process checks above.
Aggrete is Apache-2.0. No model in the decision path.