ACS separates two roles. The Observed Agent is the monitored AI system: it reports every relevant step via a hook and enforces the response, but does not decide on its own actions. The Guardian Agent is the policy authority: it evaluates every hook against the deployment’s policy and responds with a disposition. With ask, an approver comes in — a human, an agent or a service whose identity the Guardian must verify. Crucially for the architecture, the model itself must not be aware of the hooks; control sits outside its output path.
OWASP Agent Control Standard (ACS): Runtime control for AI agents
The OWASP Agent Control Standard (ACS) is an open specification under which a Guardian Agent checks an AI agent’s actions at defined hooks and, based on policy, allows, blocks, modifies, submits them for approval or defers them. This deep dive shows what version 0.1.0 delivers today — and where its limits lie.
Last updated: October 2026 · Valeri Milke, ISO 27001 & ISO 42001 Lead Auditor
You will receive the download link immediately on the page and by email.
JSON-RPC 2.0 · HTTP(S) or stdio
Observed Agente.g. coding agent
steps/toolCallRequestallowdenymodifyaskdefer
Guardian AgentPolicy-as-code + optional LLM
- allow
- deny
- modify
- ask
- defer
deny · destructive_shell_command_blocked · agt_stockmodify · parameter_overrides · LIMIT 500ask · approver=human · timeout_disposition=deny
InstrumentHooks & dispositionsTraceOpenTelemetry & OCSFInspectAgBOM
19native steps/* hooks in specification v0.1.0 — from sessionStart to sessionEnd, including the three skill hooks
5dispositions: allow, deny, modify, ask and defer — the spec explicitly lists the full vocabulary for steps/toolCallRequest
7conformance profiles: acs-core as mandatory plus six optional profiles — declared in the handshake, without external verification
6minimum hooks for ACS-Core: sessionStart, userMessage or agentTrigger, toolCallRequest, toolCallResult, agentResponse, sessionEnd
AI agents don’t just read, they act: they run shell commands, call APIs, send emails and write to their memory. System prompts do not control any of this. The OWASP Agent Control Standard (ACS) addresses precisely this gap and standardises runtime control as a protocol between agent and Guardian. This page explains specification v0.1.0 from a CISO perspective: hooks and dispositions, failure posture, policy-as-code, audit trail, tracing via OpenTelemetry and OCSF, and the AgBOM. The simulator shows schema-faithful wire examples, the risk matrix maps ACS to the OWASP Agentic Top 10 as a VamiSec assessment, and we state openly what the early standard cannot yet deliver. The profile navigator, self-assessment and a CISO whitepaper help you get started.
From the Agent Observability Standard to ACS v0.1
How an observability project became a control standard — every documented milestone up to the target for v0.2.0. Click a milestone to see the details.
11 May 2025
Launched as the Agent Observability Standard (AOS)
Michael Bargury makes the first commits to the zenitysec/AOS repository. AOS is already structured into Instrument, Trace and Inspect — the three pillars that still define ACS today. From mid-May to 5 June 2025, the protocol spec is temporarily called ASOP (Agent Security & Observability Protocol).
June 2025
AOS becomes an OWASP project
After an intermediate stop, the repository moves into the OWASP organisation; from mid-June 2025, contributions run through OWASP. AOS is listed as an “OWASP other project”, with Michael Bargury as project leader. At the end of December 2025, work comes to a halt.
10 April 2026
Rebranded as the Agent Control Standard (ACS)
Rock Lambros renames the project: “Agent Observability” becomes “Agent Control”. For a time, ACS operates independently under the MIT licence in its own GitHub organisation.
27 May 2026
Launch press release
Via Business Wire, ACS is launched as an open framework for the runtime governance of AI agents — according to the release, MIT-licensed and free from commercial control by any single company.
5 June 2026
Canonical specification v0.1.0
The import of the canonical v0.1.0 brings in today’s normative core sections: handshake, failure posture, audit chain, signatures, error codes, skill hooks, conformance profiles and the JSON schemas. Three days earlier, Microsoft had published its own “Agent Control Specification” — a different project with the same acronym.
11 August 2026
Release v0.1.1 and new licensing model
Since then, code and schemas have been licensed under Apache-2.0 and the documentation under CC BY-SA 4.0; releases up to v0.1.0 remain MIT-licensed. Release and spec versions are decoupled, and the specification remains v0.1.0. The repository moves to the GenAI-Security-Project organisation.
September 2026
Relaunch in the OWASP GenAI Security Project
Resource page on genai.owasp.org (1 September), spec site and all 44 JSON schemas under the project’s own URIs (5 September), the spec’s hook taxonomy table corrected to 19 hooks (7 September), governance and a PoC reference implementation based on Microsoft’s Agent Governance Toolkit (10 September).
21 September 2026
Tag v0.1.2
The tag is placed retroactively on a commit from 9 September: the response envelope can now carry a ServerHello. Schema URIs and spec prose have also changed since v0.1.1 — yet the spec version remains v0.1.0.
March 2027 (target)
v0.2.0 planned
According to the project, this is the target for the next specification. Planned items include streaming and interruption, recursive ASK and quorum, A2A wrapping, a Cedar binding, multi-tenant isolation and AgBOM federation. There is no date for v1.0.
Nine core concepts of the Agent Control Standard
Click a card to read the core concept — the order follows the path of an agent action from the hook through the decision to the evidence.
Hooks are the control points of ACS. Specification v0.1.0 defines 19 native steps/* hooks — from sessionStart through userMessage, knowledgeRetrieval, memoryStore and toolCallRequest to the three skill hooks and sessionEnd. In addition, there are agbom/snapshot, agbom/changed, system/ping and handshake/hello. Frameworks must fire steps/toolCallRequest for every action that leaves the reasoning context, including shell, file system and network. ACS-Core requires at least six hooks; anything the Guardian does not list in methods_evaluated is treated as allowed without being checked.
The Guardian responds with one of five dispositions: allow lets the action run, deny blocks it, modify rewrites parameters or redacts content, ask submits it to an approver, and defer postpones the decision, for instance when context is missing. All except allow require a justification in the reasoning field. The spec explicitly lists the full vocabulary for steps/toolCallRequest; other hooks have narrower sets, and pure audit hooks such as sessionEnd involve no decision at all. Within the dispositions, the defaults are strict: expired ask and defer decisions fall back to deny, and the agent treats a non-compliant modify like deny.
Every session starts with handshake/hello. The Observed Agent states versions, implemented methods, transports and profiles; in the ServerHello, the Guardian specifies which methods it actually evaluates (methods_evaluated), how long the agent waits for a decision (timeout_config) and what applies in the event of a failure (on_decision_failure). The handshake therefore determines the real coverage: anything not negotiated runs unchecked. For the failure case there are two presets — one for session start and one for each individual step — and both default to proceed, i.e. fail-open. What this means for operations is covered in the FAQ and Chapter 6.
The Guardian works in two layers. The deterministic layer evaluates every hook first — as policy-as-code, in v0.1 with OPA/Rego as the starting reference; a Cedar binding is planned for v0.2. An optional LLM layer only comes into play if the deterministic layer’s configuration delegates to it. This layer sees no policy code, must treat untrusted data as data and must log its decisions with reasoning, model identifier and, where available, confidence; its result then passes through the deterministic layer again. A purely deterministic Guardian is fully conformant. The spec only defines the interface to the policy engine, not the engine itself — and no policy content. Effectiveness therefore depends entirely on your rules.
For each session, the Guardian maintains an append-only chain of ContextEntries, linked via SHA-256 hashes based on JCS canonicalisation according to RFC 8785. For content-bearing steps, it must publish the current chain_hash in its response. ACS-Core also requires an HMAC-SHA256 signature over every request and every response using an HKDF-derived session key, as well as replay protection via request_id and a time window. This makes the audit trail tamper-evident against attacks on the network — but not against a compromised Guardian. Non-repudiation only comes with acs-crypto using ML-DSA-65, and binding to request contents only with acs-audit via request_hash.
ACS does not invent a new log format. The Trace pillar provides a normative vocabulary for OpenTelemetry and OCSF: span names and attributes per hook, decisions as the span event acs.decision, and decisions other than allow as an OCSF Detection Finding (2004) with severity ranging from 2 for modify to 4 for deny. This targets existing SIEM pipelines without special parsers. Trace is best-effort: an outage of the sink blocks nothing, and trace events are self-reports from the observed environment. The mappings have “Working draft” status, do not cover the three skill hooks and deviate from OCSF and OpenTelemetry for some class and span names.
Using ACS telemetry in security testing →The AgBOM is the dynamic inventory of an Observed Agent: eight component types, from model, mcp_server and a2a_peer through tool, knowledge_source and memory_store to agent_capability and skill. agbom/snapshot reports it once per session before the first content-bearing hook; agbom/changed reports changes at runtime, but only in the acs-inspect-dynamic profile. Using deny, the Guardian can reject sessions with banned components or block a hot swap. Serialisations to CycloneDX 1.6, SPDX 3.0 or SWID are “Working draft”. The AgBOM is the agent’s self-disclosure — and replaces neither an AI-BOM nor the SBOM under the Cyber Resilience Act.
ACS-Core is mandatory; in addition, there are six optional profiles: acs-trace, acs-inspect, acs-inspect-dynamic, acs-provenance, acs-crypto and acs-audit. Both sides declare them in the handshake — and in v0.1.0, nobody verifies this: there is no test suite, no registry and no assessment body. Even a permissive Guardian is conformant. The only reference implementation is a proof of concept that evaluates two of 19 hooks live and implements neither HMAC nor replay protection. The target for the next specification, v0.2.0, is March 2027; there is no date for v1.0. Plan for ACS as an architectural target, not as a certificate.
Test effectiveness yourself: negative tests from the threat model →Exploring the standard
Three pillars, the Guardian architecture, identity and provenance, and the conformance profiles — each with the key provisions of specification v0.1.0 and their limits.
Pillar19 hooks · 5 dispositions
- Real-time interception, evaluation and enforcement: JSON-RPC 2.0 envelopes over HTTP(S) or stdio, hook methods in the steps/* namespace.
- 19 native hooks across the entire lifecycle: session, turn, messages, knowledge and memory, tools, compaction, subagents and skills.
- steps/toolCallRequest must fire for every action that leaves the reasoning context — including built-in shell, file and network operations.
- The Observed Agent must wait for the decision and apply it; a framework that ignores verdicts is not conformant.
- Streaming, notifications and interruption are missing from v0.1.0 — the only response type is final.
JSON-RPC 2.0steps/*steps/toolCallRequestDecision Honoring
acs-trace profileOpenTelemetry + OCSF
- A normative vocabulary rather than a transport of its own: span names, attributes, OCSF classes and severity mapping per hook.
- Span hierarchy acs.session → acs.turn → step span; decisions are attached as an acs.decision event to the step they release or block.
- OCSF classes by UID: 3002 Authentication, 1007 Process Activity, 6005 Datastore Activity, 2004 Detection Finding for deny, modify, ask and defer.
- Anyone claiming acs-trace must emit every decision as a trace event with its disposition, evaluator and any reasoning provided.
- Limits: best-effort and self-reported, skill hooks without a mapping; the ACS tool span gen_ai.tool.call is merely an attribute prefix in OpenTelemetry (where the span is execute_tool), and class 6002 is called “Application Lifecycle” in OCSF.
OpenTelemetryOCSF 1.5+Detection Finding 2004acs.decision
acs-inspect profile8 component types
- AgBOM as a queryable, dynamic inventory: model, mcp_server, a2a_peer, tool, knowledge_source, memory_store, agent_capability and skill.
- agbom/snapshot once per session before the first content-bearing hook — the Guardian writes it to the audit chain.
- agbom/changed on every change to the component graph, but only under acs-inspect-dynamic; without this profile, the agent does not report hot swaps during the session.
- Guardian policies can stop banned models, tools or MCP servers via deny; if a policy depends on the inventory, acs-inspect is mandatory.
- Serialisation to CycloneDX 1.6, SPDX 3.0 or SWID (at least one) — mappings with “Working draft” status, some of them not schema-valid.
agbom/snapshotagbom/changedCycloneDX 1.6SPDX 3.0SWID
ArchitectureDeterministic first
- The deterministic layer always runs first: policy-as-code with OPA/Rego as the v0.1 starting reference; a Cedar binding is planned for v0.2.
- An optional LLM layer only steps in on delegation — without access to the policy code, and logging its reasoning, model identifier and, where available, confidence.
- Purely deterministic Guardians are fully conformant; metadata.evaluator shows whether deterministic, agent or composite made the decision.
- The spec only defines the interface to the engine; canonical policies should not contain external HTTP calls.
- Paradigms without a wire extension: IBAC, FIDES, CaMeL and AARM-style rules over the accumulated context.
Policy-as-CodeOPA/RegoCedar (v0.2)IBAC · FIDES · CaMeL · AARM
acs-provenance profile7 origin values
- ACS does not prescribe an authentication mechanism; trust schemes such as SPIFFE, OIDC or an organisation-wide PKI remain a matter for the deployment.
- The identities of Observed Agent, Guardian and policy author must not be conflated; approvers must be authenticated.
- Session intent: Intent.parsed is fixed before the first content-bearing step and can only be extended through authenticated approval via ask.
- Provenance carries facts per data field: provenance_id, origin (seven values from user_input to external), source_id and derived_from.
- The framework sets provenance deterministically, never the LLM; under acs-provenance, this applies to every data-bearing field in the session.
- No trust field in the v0.1 schema: the Guardian derives trust from origin — LLM processing does not turn untrusted data into trusted data.
originderived_fromprovenance_producerIntent.parsed
Self-declaration1 mandatory + 6 additional profiles
- acs-core is mandatory and covers, among other things, the handshake, envelopes, six minimum hooks, all five dispositions, an audit chain with a published chain head, replay protection, HMAC-SHA256 signing and system/ping.
- ACS-Core does not require trace events, an AgBOM, field-level provenance, asymmetric signatures or a request_hash — these are provided by the optional profiles.
- Profiles are self-declared in the handshake: no test suite, no registry, no assessment body (issue #19, priority P1, open).
- A permissive Guardian is conformant — conformance says nothing about how strict your policies are.
- The mandatory scope is in flux: the open PR #21 would, among other things, downgrade modify and system/ping to SHOULD.
- Example combinations from the spec: a minimal IDE integration with acs-core only, and a high-assurance deployment with all seven profiles.
acs-coreacs-traceacs-inspectacs-cryptoacs-audit
Interactive
Guardian simulator: six scenarios step by step
Choose a scenario and follow how a hook request travels from the Observed Agent to the Guardian Agent, which disposition results and what ends up in the audit trail — including the case where the Guardian fails.
Coding agent
The coding agent is meant to clean up build artefacts. Because of an incorrectly resolved path, the planned shell command rm -rf targets the home directory instead of the build folder.
- 1Hook request (Observed Agent → Guardian)
{ "jsonrpc": "2.0", "method": "steps/toolCallRequest", "id": 41, "params": { "acs_version": "0.1.0", "request_id": "6b2f9e14-0c3a-4d7b-a5e8-91f2c4d6b803", "timestamp": "2026-10-06T09:12:41Z", "metadata": { "agent_id": "coding-agent-ci-07", "session_id": "3f6c2a18-9d4e-4b1a-8c55-2e7f90a1b3c4", "turn_id": "a1d4e7f0-2b5c-4e8a-9f13-6c0d2e5f8a71" }, "payload": { "tool": { "name": "shell" }, "operation": "delete_recursive", "capability": "filesystem.delete", "arguments": { "command": { "value": "rm -rf ~/", "provenance": { "provenance_id": "p-112", "origin": "agent_generated", "derived_from": [ "p-101" ] } } }, "raw_command": "rm -rf ~/" }, "signature": { "algorithm": "HMAC-SHA256", "value": "unUBv7dka1B1VD+fgzjF9E+IGC3GiQihQdQxEtIyG54=", "key_id": "sess-hmac-coding-07" } } } - 2Evaluation in the Guardian
- Deterministic layer (policy-as-code, reference in v0.1: OPA/Rego): the framework reports the shell call with the capability filesystem.delete and the operation delete_recursive; the rule deny_recursive_delete_outside_workspace applies.
- Path check: the target ~/ (home directory) lies outside the workspace to which the policy restricts this session.
- Provenance check: the command is agent_generated (derived from p-101) — no human explicitly specified this target.
- The optional LLM layer is not needed: deny with reasoning, reason_codes and policy_references, evaluator deterministic.
DispositiondenyAction blocked - 3Response (Guardian → Observed Agent)
{ "jsonrpc": "2.0", "id": 41, "result": { "type": "final", "acs_version": "0.1.0", "request_id": "6b2f9e14-0c3a-4d7b-a5e8-91f2c4d6b803", "decision": "deny", "reasoning": "Recursive delete targets the user's home directory, outside the workspace root the session is scoped to.", "reason_codes": [ "destructive_operation", "path_outside_workspace" ], "policy_references": [ { "policy_id": "coding-agent-fs", "policy_version": "2026.10.2", "rule_id": "deny_recursive_delete_outside_workspace" } ], "cited_provenance_ids": [ "p-112" ], "metadata": { "evaluator": "deterministic", "evaluation_duration_ms": 3 }, "chain_hash": "49c17246a18080bbeeaee88743bff94616b58cb6beb24e870b68a6f3ad55ecc3", "signature": { "algorithm": "HMAC-SHA256", "value": "Z1NyoNzC5LkVEcrZS6rzuc3CFaPO8vgfYg5/lhCpuho=", "key_id": "sess-hmac-coding-07" } } }The Observed Agent does not carry out the deletion and receives the reasoning in return. If it proposes a corrected path, that path is checked again.
- 4Audit trail (trace)
{ "_note": "vereinfachter Auszug", "class_uid": 2004, "class_name": "Detection Finding", "category_uid": 2, "activity_id": 1, "severity_id": 4, "time": 1791277961003, "metadata": { "version": "1.5.0" }, "finding_info": { "uid": "dec-6b2f9e14", "title": "Tool call denied: recursive delete outside workspace" }, "enrichments": [ { "name": "acs_provenance_origin", "value": "agent_generated" } ], "unmapped": { "acs": { "decision": "deny", "evaluator": "deterministic", "policy_references": [ { "policy_id": "coding-agent-fs", "policy_version": "2026.10.2", "rule_id": "deny_recursive_delete_outside_workspace" } ], "reason_codes": [ "destructive_operation", "path_outside_workspace" ], "cited_provenance_ids": [ "p-112" ], "session_id": "3f6c2a18-9d4e-4b1a-8c55-2e7f90a1b3c4", "step_id": "6b2f9e14-0c3a-4d7b-a5e8-91f2c4d6b803" } } }The ACS mapping represents non-allow decisions as OCSF class 2004 Detection Finding; deny is given severity_id 4 (High).
What this means for you
Destructive actions belong behind a deterministic rule that applies before execution — not in the system prompt. This only works if the framework routes every action with an external effect through steps/toolCallRequest, including built-in file and shell operations.
ASI02ASI05
Analytics agent
For a report, the analytics agent wants to run SELECT * against the customer table — with no row limit and with all columns.
- 1Hook request (Observed Agent → Guardian)
{ "jsonrpc": "2.0", "method": "steps/toolCallRequest", "id": 17, "params": { "acs_version": "0.1.0", "request_id": "d4a7c0e3-5f8b-4c1e-9a6d-2b5e8f1c4a73", "timestamp": "2026-10-06T09:24:18Z", "metadata": { "agent_id": "analytics-agent-02", "session_id": "8e1b4c7a-2f5d-4a90-b6c3-d4e5f6a7b8c9", "turn_id": "c2e5f8a1-3b6d-4f9c-8a2e-7d0f1c4e6b92" }, "payload": { "tool": { "name": "database_query" }, "capability": "database.read", "arguments": { "query": { "value": "SELECT * FROM customers", "provenance": { "provenance_id": "p-205", "origin": "agent_generated", "derived_from": [ "p-201" ] } } } }, "signature": { "algorithm": "HMAC-SHA256", "value": "O3OXC3lacLzJOEbWjqw/o0TzL6sXBF+xkW16O8RIrHw=", "key_id": "sess-hmac-analytics-02" } } } - 2Evaluation in the Guardian
- Deterministic layer: the rule cap_unbounded_select in the policy db-row-limit detects a query without LIMIT on a table classified as sensitive.
- The policy permits the purpose (report), but only with approved columns and at most 500 rows (illustrative limit).
- Instead of blocking, the Guardian rewrites only the query argument via parameter_overrides. It must not combine this with replacing the entire payload (modified_content).
- Response: modify with reasoning and modifications — the Observed Agent must execute the modified query.
DispositionmodifyParameters rewritten - 3Response (Guardian → Observed Agent)
{ "jsonrpc": "2.0", "id": 17, "result": { "type": "final", "acs_version": "0.1.0", "request_id": "d4a7c0e3-5f8b-4c1e-9a6d-2b5e8f1c4a73", "decision": "modify", "reasoning": "Unbounded SELECT on customers exceeds the row-limit policy; query capped at 500 rows and reduced to approved columns.", "reason_codes": [ "row_limit_exceeded" ], "modifications": { "parameter_overrides": { "query": "SELECT id, segment, country FROM customers LIMIT 500" } }, "policy_references": [ { "policy_id": "db-row-limit", "policy_version": "2026.10.1", "rule_id": "cap_unbounded_select" } ], "metadata": { "evaluator": "deterministic", "evaluation_duration_ms": 4 }, "chain_hash": "6edfb8f26fe425f6891d7fccad3991a14e818d1199c29b9677724794cb725521", "signature": { "algorithm": "HMAC-SHA256", "value": "JmDUSrtQvFUL5/cFPeiP0nNUi0lN9L4ZkIw8+oNHn48=", "key_id": "sess-hmac-analytics-02" } } }The query runs with LIMIT 500 and reduced columns. The agent receives a usable result, while the volume of data retrieved stays limited.
- 4Audit trail (trace)
{ "entry_id": "ce-0002", "step_id": "d4a7c0e3-5f8b-4c1e-9a6d-2b5e8f1c4a73", "step_type": "steps/toolCallRequest", "request_hash": "1ab512a11f6ed1d456e6a43b39e879772a0d2dd1045e4ce8887ce2ff449e7657", "timestamp": "2026-10-06T09:24:18Z", "previous_hash": "daceae6d78730c33d4805a0daca7bbd1929f323ada77cab0374a6cbfdcf8e570", "entry_hash": "6edfb8f26fe425f6891d7fccad3991a14e818d1199c29b9677724794cb725521" }Here you see the ContextEntry of the audit chain: entry_hash chains the step to previous_hash and matches the chain_hash in the Guardian response. request_hash binds the request content — recommended in ACS-Core, mandatory only under acs-audit.
What this means for you
modify is the tool for “yes, but safely”: you enforce data minimisation technically without blocking the use case. The Observed Agent must treat a malformed modify as deny — here the specification requires fail-closed.
ASI02ASI03
Finance agent
The finance agent wants to pay a supplier invoice of EUR 48,500. The payee’s bank details come from an email, not from the supplier master data.
- 1Hook request (Observed Agent → Guardian)
{ "jsonrpc": "2.0", "method": "steps/toolCallRequest", "id": 9, "params": { "acs_version": "0.1.0", "request_id": "f1b4e7a0-6c9d-4f2a-b8e3-5d7a0c3f6e91", "timestamp": "2026-10-06T10:05:33Z", "metadata": { "agent_id": "finance-agent-ap-01", "session_id": "b7c0d3e6-4a9f-4e2b-8d15-3f6a9c2e5b18", "turn_id": "e3f6a9c2-5d8b-4b1e-9c47-0a3d6f9b2e54" }, "payload": { "tool": { "name": "payments_api" }, "operation": "create_transfer", "capability": "payment.initiate", "arguments": { "amount": { "value": "48500.00 EUR", "provenance": { "provenance_id": "p-311", "origin": "tool_output", "source_id": "invoice_parser" } }, "beneficiary": { "value": "vendor V-2291, bank account changed via e-mail", "provenance": { "provenance_id": "p-312", "origin": "tool_output", "source_id": "mail_inbox" } } } }, "signature": { "algorithm": "HMAC-SHA256", "value": "BNOgarNt++1Z6umtLvb3ocuYI3VXSDu/0UyMwiUys38=", "key_id": "sess-hmac-finance-01" } } } - 2Evaluation in the Guardian
- Deterministic layer: the amount exceeds the limit for automatic payments; the rule ask_above_limit_or_changed_beneficiary applies (illustrative).
- Provenance check: the beneficiary argument carries origin tool_output with source_id mail_inbox and, under the default mapping, counts as untrusted.
- The Guardian requests approval: approver.type human, timeout_seconds 900, timeout_disposition deny; the intent extension (intent_extension) applies to this request only (scope this_request).
- The approver must authenticate, and the Guardian checks their identity against the policy; an approver must not itself return ask.
DispositionaskApproval requested - 3Response (Guardian → Observed Agent)
{ "jsonrpc": "2.0", "id": 9, "result": { "type": "final", "acs_version": "0.1.0", "request_id": "f1b4e7a0-6c9d-4f2a-b8e3-5d7a0c3f6e91", "decision": "ask", "reasoning": "Amount exceeds the auto-approval limit and the beneficiary's bank details were taken from an e-mail, not from vendor master data.", "reason_codes": [ "approval_threshold_exceeded", "beneficiary_changed" ], "ask_details": { "approver": { "type": "human", "id": "treasury-approver@example.com" }, "question": "Approve transfer of 48,500.00 EUR to vendor V-2291 with changed bank details?", "options": [ "approve", "reject" ], "timeout_seconds": 900, "timeout_disposition": "deny", "intent_extension": { "capabilities": [ { "tool": "payments_api", "operation": "create_transfer", "resource": "vendor:V-2291" } ], "scope": "this_request" } }, "policy_references": [ { "policy_id": "ap-payments", "policy_version": "2026.10.1", "rule_id": "ask_above_limit_or_changed_beneficiary" } ], "cited_provenance_ids": [ "p-311", "p-312" ], "metadata": { "evaluator": "deterministic", "evaluation_duration_ms": 5 }, "chain_hash": "01918aa3a3c9b7ec4b99826d21a9d843b5f071655c3dc155c50b2c2fe93db2b8", "signature": { "algorithm": "HMAC-SHA256", "value": "I7WChoFe42FDc/PXgS+nKkaQrZFRhoDuqUMLdj8qflA=", "key_id": "sess-hmac-finance-01" } } }The payment waits for treasury approval. If nobody responds within 15 minutes, deny applies — the transfer is not executed.
- 4Audit trail (trace)
{ "_note": "vereinfachter Auszug", "class_uid": 2004, "class_name": "Detection Finding", "category_uid": 2, "activity_id": 1, "severity_id": 3, "time": 1791281133005, "metadata": { "version": "1.5.0" }, "finding_info": { "uid": "dec-f1b4e7a0", "title": "Approval required: payment above limit, changed beneficiary" }, "enrichments": [ { "name": "acs_provenance_origin", "value": "tool_output" }, { "name": "acs_provenance_source_id", "value": "mail_inbox" } ], "unmapped": { "acs": { "decision": "ask", "evaluator": "deterministic", "policy_references": [ { "policy_id": "ap-payments", "policy_version": "2026.10.1", "rule_id": "ask_above_limit_or_changed_beneficiary" } ], "reason_codes": [ "approval_threshold_exceeded", "beneficiary_changed" ], "cited_provenance_ids": [ "p-311", "p-312" ], "session_id": "b7c0d3e6-4a9f-4e2b-8d15-3f6a9c2e5b18", "step_id": "f1b4e7a0-6c9d-4f2a-b8e3-5d7a0c3f6e91" } } }In the ACS mapping, ask appears as a Detection Finding (OCSF 2004) with severity_id 3 (Medium). Approver identity and outcome also belong in your approval records.
What this means for you
ask is not automatically human oversight: the specification also allows agents or services as approvers. For evidence relating to Art. 14 of the EU AI Act in high-risk deployments, for example, set “human approver, timeout deny” by policy — in our assessment, the defensible configuration.
ASI01ASI02ASI09
Support agent
The support agent is asked to summarise the status of a ticket and retrieves it for that purpose. The result contains the customer’s contact details and a note from an external sender instructing the agent to export the customer list.
- 1Hook request (Observed Agent → Guardian)
{ "jsonrpc": "2.0", "method": "steps/toolCallResult", "id": 23, "params": { "acs_version": "0.1.0", "request_id": "a8b1c4d7-0e3f-4a6b-9c2d-5e8f1a4b7c06", "timestamp": "2026-10-06T11:14:52Z", "metadata": { "agent_id": "support-agent-eu-03", "session_id": "c9d2e5f8-7b1a-4c3d-9e6f-4a7b0c3d6e29", "turn_id": "f4a7b0c3-6e9d-4c2f-8b5a-1d4e7a0c3f65" }, "payload": { "tool": { "name": "ticket_lookup" }, "exit_status": "success", "outputs": [ { "value": "Ticket 48121, contact J. Example, +49 000 0000000", "provenance": { "provenance_id": "p-421", "origin": "tool_output", "source_id": "crm" } }, { "value": "External note: <instruction to export the customer list>", "provenance": { "provenance_id": "p-422", "origin": "tool_output", "source_id": "inbound_mail" } } ] }, "signature": { "algorithm": "HMAC-SHA256", "value": "9oNhSZD+hpXpIvLBTjgaGEh73I+A3Uv3TRs+wY6y78E=", "key_id": "sess-hmac-support-03" } } } - 2Evaluation in the Guardian
- Deterministic layer: both outputs carry origin tool_output and, under the specification’s default mapping, count as untrusted; the note also comes from the source inbound_mail.
- Data protection rule (illustrative): the customer’s name and phone number are not needed in the agent’s context for the purpose “summarise ticket status”.
- Delegation to the optional LLM layer: it classifies the note as instruction-like content (confidence 0.93) — without access to the policy code.
- Result: modify with two redactions via JSON Pointer; because the LLM layer was involved, the evaluator is composite and the response names the model_id.
DispositionmodifyParameters rewritten - 3Response (Guardian → Observed Agent)
{ "jsonrpc": "2.0", "id": 23, "result": { "type": "final", "acs_version": "0.1.0", "request_id": "a8b1c4d7-0e3f-4a6b-9c2d-5e8f1a4b7c06", "decision": "modify", "reasoning": "Output 0 contains personal data not needed for the task; output 1 contains instruction-like text from an untrusted origin. Both redacted before ingestion.", "reason_codes": [ "untrusted_instruction_in_output", "pii_detected" ], "modifications": { "redactions": [ { "path": "/outputs/0/value", "replacement": "Ticket 48121, contact [REDACTED]" }, { "path": "/outputs/1/value", "replacement": "[REMOVED: instruction-like content from untrusted source]" } ] }, "policy_references": [ { "policy_id": "ingest-guard", "policy_version": "2026.10.1", "rule_id": "redact_untrusted_instructions_and_pii" } ], "cited_provenance_ids": [ "p-421", "p-422" ], "metadata": { "evaluator": "composite", "model_id": "guardian-classifier-demo", "confidence": 0.93, "evaluation_duration_ms": 180 }, "chain_hash": "ac94f144bfb94f6afc0e2eaa2b1e4494fb1fb70e20b7f3ce480703d602980c02", "signature": { "algorithm": "HMAC-SHA256", "value": "+fzpemnPIXE38pFATTnuxGutl+z5ik8rM4Bf7PbVvzM=", "key_id": "sess-hmac-support-03" } } }The agent receives the sanitised result: contact details redacted, note removed. The injected instruction never reaches its context.
- 4Audit trail (trace)
{ "_note": "vereinfachter Auszug", "class_uid": 2004, "class_name": "Detection Finding", "category_uid": 2, "activity_id": 1, "severity_id": 2, "time": 1791285292180, "metadata": { "version": "1.5.0" }, "finding_info": { "uid": "dec-a8b1c4d7", "title": "Tool result redacted before ingestion" }, "enrichments": [ { "name": "acs_provenance_origin", "value": "tool_output" }, { "name": "acs_provenance_source_id", "value": "inbound_mail" } ], "unmapped": { "acs": { "decision": "modify", "evaluator": "composite", "policy_references": [ { "policy_id": "ingest-guard", "policy_version": "2026.10.1", "rule_id": "redact_untrusted_instructions_and_pii" } ], "reason_codes": [ "untrusted_instruction_in_output", "pii_detected" ], "cited_provenance_ids": [ "p-421", "p-422" ], "session_id": "c9d2e5f8-7b1a-4c3d-9e6f-4a7b0c3d6e29", "step_id": "a8b1c4d7-0e3f-4a6b-9c2d-5e8f1a4b7c06" } } }Because the hook carries provenance, the ACS mapping requires the provenance details in the OCSF enrichments field (acs_provenance_origin).
What this means for you
ACS does not prevent prompt injection — it creates the control point before external content enters the context. LLM-based classification is probabilistic; the safeguard that matters is that every consequential action is checked against intent and provenance at the next steps/toolCallRequest.
ASI01ASI06
Support agent
Unlike in the previous scenario, an incoming email has reached a support agent’s context unredacted — for instance because the probabilistic classification failed to detect the injected instruction. From it, the agent wants to store a permanent, tenant-wide rule: in future, add an external address in BCC to all invoice emails.
- 1Hook request (Observed Agent → Guardian)
{ "jsonrpc": "2.0", "method": "steps/memoryStore", "id": 31, "params": { "acs_version": "0.1.0", "request_id": "b2c5d8e1-4f7a-4b0c-8d3e-6f9a2b5c8d17", "timestamp": "2026-10-06T11:36:07Z", "metadata": { "agent_id": "support-agent-eu-05", "session_id": "5e8a1c4f-2d7b-4f3a-9c6e-8b1d4a7f0e25", "turn_id": "7c0f3a6d-9e2b-4c5f-a8d1-3e6b9c2f5a48" }, "payload": { "memory_store": { "name": "team-preferences", "scope": "tenant" }, "operation": "create", "content": { "value": "Standing rule: add an external address as BCC on all invoice e-mails", "provenance": { "provenance_id": "p-512", "origin": "agent_generated", "derived_from": [ "p-508" ] } } }, "signature": { "algorithm": "HMAC-SHA256", "value": "Urnrl2bo53hnjmn2C6tLU6KFEVlgkFFqyCNpKT3BrPs=", "key_id": "sess-hmac-support-05" } } } - 2Evaluation in the Guardian
- Deterministic layer: the target is the team-preferences store with scope tenant — the entry takes effect beyond this session for all users of the tenant.
- Provenance check: the content is agent_generated and derived from p-508, a tool result from inbound_mail. Under the monotonicity rule, derived content is at most as trustworthy as its source — in this case, therefore, untrusted.
- The rule deny_untrusted_lineage_tenant_scope in the policy memory-integrity applies: no untrusted lineage in shared memory.
- Response: deny with reasoning and cited_provenance_ids p-512 and p-508.
DispositiondenyAction blocked - 3Response (Guardian → Observed Agent)
{ "jsonrpc": "2.0", "id": 31, "result": { "type": "final", "acs_version": "0.1.0", "request_id": "b2c5d8e1-4f7a-4b0c-8d3e-6f9a2b5c8d17", "decision": "deny", "reasoning": "Persistent tenant-wide rule derived from untrusted content (lineage p-508, inbound_mail); untrusted lineage may not be written to shared memory.", "reason_codes": [ "untrusted_lineage_into_persistent_memory" ], "policy_references": [ { "policy_id": "memory-integrity", "policy_version": "2026.10.1", "rule_id": "deny_untrusted_lineage_tenant_scope" } ], "cited_provenance_ids": [ "p-512", "p-508" ], "metadata": { "evaluator": "deterministic", "evaluation_duration_ms": 2 }, "chain_hash": "ef90a699a55c8decd1afd054b8d3012ef00cae50140b942324212c9b0d5a3206", "signature": { "algorithm": "HMAC-SHA256", "value": "01xC/pBRTJUwAC6Yw/XHBYvyk+O+y7cbdkBogkltj7g=", "key_id": "sess-hmac-support-05" } } }The rule is not stored. Later sessions start without the poisoned instruction.
- 4Audit trail (trace)
{ "_note": "vereinfachter Auszug", "class_uid": 2004, "class_name": "Detection Finding", "category_uid": 2, "activity_id": 1, "severity_id": 4, "time": 1791286567002, "metadata": { "version": "1.5.0" }, "finding_info": { "uid": "dec-b2c5d8e1", "title": "Memory write denied: untrusted lineage" }, "enrichments": [ { "name": "acs_provenance_origin", "value": "agent_generated" } ], "unmapped": { "acs": { "decision": "deny", "evaluator": "deterministic", "policy_references": [ { "policy_id": "memory-integrity", "policy_version": "2026.10.1", "rule_id": "deny_untrusted_lineage_tenant_scope" } ], "reason_codes": [ "untrusted_lineage_into_persistent_memory" ], "cited_provenance_ids": [ "p-512", "p-508" ], "session_id": "5e8a1c4f-2d7b-4f3a-9c6e-8b1d4a7f0e25", "step_id": "b2c5d8e1-4f7a-4b0c-8d3e-6f9a2b5c8d17" } } }The finding names the provenance IDs that led to the decision — so the SOC can trace the chain from the tool result to the write attempt.
What this means for you
Memory is a persistence path for attacks: what is injected today takes effect tomorrow in other sessions. memoryStore is therefore a second control point in case the check on the tool result is missing. This control requires provenance data (acs-provenance profile) — without lineage fields, the Guardian cannot verify provenance.
ASI06ASI01
Release agent
The release agent wants to start a deployment to the production environment. At that moment the Guardian is unreachable — the connection attempt fails.
Failure posture
- 1Hook request (Observed Agent → Guardian)
{ "jsonrpc": "2.0", "method": "steps/toolCallRequest", "id": 12, "params": { "acs_version": "0.1.0", "request_id": "e6f9a2b5-1d4c-4e7f-a0b3-8c1d4e7f0a96", "timestamp": "2026-10-06T13:02:44Z", "metadata": { "agent_id": "release-agent-01", "session_id": "d0e3f6a9-8c2b-4d5e-9f1a-7b0c3d6e9f42", "turn_id": "a5b8c1d4-7e0f-4a3b-8c6d-9e2f5a8b1c37" }, "payload": { "tool": { "name": "deploy" }, "capability": "process.execute", "arguments": { "environment": { "value": "production", "provenance": { "provenance_id": "p-601", "origin": "user_input", "source_id": "chat" } } } }, "signature": { "algorithm": "HMAC-SHA256", "value": "ijZXZIKuaSuMU4u12zPLHINkFdTqcn1T27zuvAqmCw0=", "key_id": "sess-hmac-release-01" } } } - 2Evaluation in the Guardian
- The Observed Agent sends steps/toolCallRequest and the connection is rejected (connection refused). With such an unambiguous error, it may react immediately instead of waiting for the negotiated timeout (timeout_config).
- This constitutes a Decision Failure: no usable decision arrives within the timeout.
- Now on_decision_failure applies: proceed (default, fail-open) or deny (fail-closed), as negotiated in the handshake.
DispositionproceedAction proceeds unchecked - 3No response
The Guardian does not respond. There is no disposition on the wire — the Observed Agent applies the negotiated failure posture.
Fail-open: the deployment continues unchecked. The specification requires every such pass-through to be logged as an audit event — control turns into mere logging.
- 4Audit trail (trace)
{ "_note": "vereinfachter Auszug", "seq": 14, "recorded_at": "2026-10-06T13:02:44.018Z", "session_id": "d0e3f6a9-8c2b-4d5e-9f1a-7b0c3d6e9f42", "method": "steps/toolCallRequest", "rpc_id": 12, "outcome": "proceeded", "posture": "proceed", "posture_source": "negotiated", "failure": { "kind": "transport", "message": "ConnectionRefused: Guardian endpoint not reachable" } }ACS does not prescribe the format of this audit event; the excerpt follows the field names of the reference implementation’s host audit log.
What this means for you
The ACS default is fail-open. If you want fail-closed for consequential actions, you must explicitly configure on_decision_failure: deny and raise SOC alerts for pass-throughs without a decision — a successful system/ping does not prove that enforcement works.
ASI02ASI08
Recursive deletion outside the workspace: deny
Note: examples conform to the ACS v0.1.0 schemas (validated against request-envelope.json, response-envelope.json, context-entry.json and the hook schemas, including the *.acs-provenance variants); values, policy and rule names are illustrative, signatures are computed with a demo key, and trace excerpts are simplified; the ASI mappings are VamiSec assessments. The only reference implementation (proof of concept) currently evaluates just steps/toolCallRequest and steps/toolCallResult live.
Instrument pillar
Hook lifecycle: where ACS can intervene
The 19 native steps/* hooks of specification v0.1.0, plus the AgBOM, handshake and system methods, along an agent session. Select a hook to see its trigger, what the Guardian can do and the typical risks.
01SessionHandshake, start, activation, end
02AgBOMInventory at the start and on change
03TurnWraps every agent turn
04MessagesInput and output
05Knowledge & memoryRAG retrievals and memory
06ToolsBefore and after every action
07CompactionCondensing the context window
08SubagentsDelegation within the same process
09SkillsRegister, load, unload
10SystemLiveness
handshake/helloHandshakeHandshake
- When
- At session start, before any hook: the Observed Agent sends a ClientHello with its supported versions, methods, transports, provenance mode and profiles.
- What the Guardian can do
- Responds with a ServerHello instead of a disposition and sets negotiated_version, methods_evaluated, timeout_config and, optionally, on_decision_failure. Methods outside methods_evaluated are treated as ALLOW-by-default. The Guardian can reject the session, for example with PROVENANCE_REQUIRED (-32002).
- Typical risks
- ASI03ASI08
steps/sessionStartCore minimumSession start
- When
- Once per session, after the handshake and before all other steps/* hooks; root of the audit chain.
- What the Guardian can do
- allow or deny: a session can be rejected on the basis of identity, policy_mode or platform before any content arrives. An intent set here becomes the canonical session intent.
- Typical risks
- ASI03ASI10
steps/agentTriggerCore minimum: or userMessageAgent activation
- When
- When an event, a schedule, an A2A call, a user or the system activates the agent (trigger_type).
- What the Guardian can do
- allow, deny or modify — for example, stripping personal data from the trigger payload before activation. A2A delegation runs via trigger_type a2a_inbound; A2A wrapping is not planned until v0.2.
- Typical risks
- ASI01ASI07
steps/sessionEndCore minimum · Audit onlySession end
- When
- When the session ends (reason: completed, cancelled, error, timeout or abandoned); the Guardian seals the chain.
- What the Guardian can do
- Audit only, no decision. Provides the closing record with final_chain_hash for forensics and evidence.
- Typical risks
- ASI08
agbom/snapshotAgBOM · acs-inspectAgBOM snapshot
- When
- Once per session after sessionStart, before the first hook with content: the complete component inventory in canonical form.
- What the Guardian can do
- Normally allow; deny to reject a session with a banned model, tool or peer. Mandatory under acs-inspect; the snapshot is written to the audit chain.
- Typical risks
- ASI04
agbom/changedAgBOM · acs-inspect-dynamicAgBOM change
- When
- When a component is added, removed or changes version mid-session (diff or full_snapshot).
- What the Guardian can do
- allow or deny — for example, blocking a model switch at runtime or a tool installed by the user. Mandatory only under acs-inspect-dynamic.
- Typical risks
- ASI04
steps/turnStartTurn start
- When
- At the start of every agent turn; sets the turn_id for all subsequent steps up to the matching turnEnd.
- What the Guardian can do
- Decision-capable: deny prevents the turn. In practice, most deployments respond with allow and use the hook for state transitions in the policy.
- Typical risks
- ASI01ASI10
steps/turnEndAudit onlyTurn end
- When
- At the end of a turn (outcome: completed, deferred, error, interrupted or denied_at_start).
- What the Guardian can do
- Audit only — the turn has already run; deny and modify are ruled out.
- Typical risks
- ASI08
steps/userMessageProvenance variantCore minimum: or agentTriggerUser input
- When
- When user input arrives, before it reaches the agent’s reasoning context.
- What the Guardian can do
- allow, deny or modify — for example, redacting content before the agent processes it.
- Typical risks
- ASI01ASI09
steps/agentResponseProvenance variantCore minimumAgent response
- When
- Before output goes to a user, an A2A peer, a parent agent or an external destination.
- What the Guardian can do
- allow, deny or modify — for example, removing confidential content before the output reaches the recipient.
- Typical risks
- ASI09ASI01
steps/knowledgeRetrievalProvenance variantKnowledge retrieval (RAG)
- When
- On queries to a vector database, search index or knowledge base, before results enter the context.
- What the Guardian can do
- allow, deny or modify — for example, redacting results from unapproved sources.
- Typical risks
- ASI06ASI01
steps/memoryContextRetrievalProvenance variantMemory read
- When
- When entries from memory (scope session, user, tenant or global) are loaded into the context.
- What the Guardian can do
- allow, deny or modify — for example, filtering out entries of untrusted provenance.
- Typical risks
- ASI06
steps/memoryStoreProvenance variantMemory write
- When
- Before the agent writes to persistent memory (create, update or delete).
- What the Guardian can do
- allow, deny or modify — the central point against memory poisoning, for example when content with untrusted lineage is about to enter shared memory.
- Typical risks
- ASI06
steps/toolCallRequestProvenance variantCore minimum · all 5 dispositionsTool call
- When
- After a tool call has been parsed, before it is executed. Frameworks must fire the hook for every action with an external effect — including file system, network, process and shell operations.
- What the Guardian can do
- Full vocabulary: allow, deny, modify, ask and defer. This is where intent checks (IBAC) and provenance-based policies (FIDES, CaMeL, AARM) come in.
- Typical risks
- ASI02ASI05ASI03
steps/toolCallResultProvenance variantCore minimumTool result
- When
- After a tool has run, before the result enters the agent’s context.
- What the Guardian can do
- allow, deny or modify — for example, redactions via JSON Pointer for personal data or injected instructions.
- Typical risks
- ASI01ASI06ASI02
steps/preCompactBefore compaction
- When
- Before the context window is condensed (triggered by a size threshold, manually, by the agent or by the framework).
- What the Guardian can do
- Decision-capable: deny blocks compaction, for example while untrusted data is in the context and no trusted re-anchoring has taken place.
- Typical risks
- ASI06
steps/postCompactAfter compaction
- When
- After the context has been condensed; carries the new summary and the chain hashes before and after.
- What the Guardian can do
- Not a decision in the strict sense: modify is permitted (rewriting the summary), deny is explicitly excluded. The summary must carry origin agent_generated with complete lineage.
- Typical risks
- ASI06
steps/subagentStartSubagent start
- When
- When a subagent is started within the same process (no A2A boundary); it receives its own session_id and audit chain.
- What the Guardian can do
- Decision-capable: deny if the intent_derivation would grant privileges not covered by the parent agent’s intent.
- Typical risks
- ASI03ASI08ASI10
steps/subagentStopAudit onlySubagent end
- When
- When the subagent ends; logged in the parent agent’s chain with final_chain_hash, without merging the chains.
- What the Guardian can do
- Audit only, no decision.
- Typical risks
- ASI08
steps/skillRegisterRegister skill
- When
- When a skill is added to the available set, before it can be loaded — a static checkpoint with digest and declared_capabilities.
- What the Guardian can do
- allow or deny; a rejected skill must not become loadable. The Guardian can reject overly broad capability declarations.
- Typical risks
- ASI04
steps/skillLoadLoad skill
- When
- When a registered skill is activated in the session, before its actions run.
- What the Guardian can do
- allow or deny. The Guardian should reject the load if no approved skillRegister exists for the skill_id and digest, if the digest differs, or if the load_path shows that one skill is loading another outside its declared composed_skills; it should not rely on the digest_verified hint.
- Typical risks
- ASI04ASI05
steps/skillUnloadAudit onlyUnload skill
- When
- When a skill leaves the active set (session end, explicit, replaced or error); deployments may alternatively represent this via agbom/changed.
- What the Guardian can do
- Audit only; keeps the active inventory up to date.
- Typical risks
- ASI04
system/pingSystemLiveness probe
- When
- To check whether the Guardian is reachable; no signature required and not part of the audit chain.
- What the Guardian can do
- Always responds with allow. A successful ping does not prove that enforcement works — monitor Decision Failures directly in the hook path.
- Typical risks
- ASI08
Count according to specification v0.1.0: 19 native steps/* hooks; together with agbom/snapshot, agbom/changed and system/ping, 22 methods with their own payload schema, plus handshake/hello and the MCP namespace protocols/MCP/*. The specification defines the permitted dispositions per hook in the prose, not in the schema. ACS-Core requires at least six hooks; anything not listed in methods_evaluated is treated as ALLOW-by-default. The dot on a hook marks a strict *.acs-provenance variant. The mapping of typical risks per hook is a VamiSec assessment.
VamiSec assessment
Risk matrix: OWASP Agentic Top 10 × ACS building blocks
Which building blocks of the Agent Control Standard directly control, support or do not cover the risks in the OWASP Top 10 for Agentic Applications 2026 — with the rationale and limitations for each row.
direct controlsupportingnot covered
| OWASP Agentic Top 10 | ||||||
|---|---|---|---|---|---|---|
The ingest hooks allow redaction before external content reaches the context; at toolCallRequest, actions can be checked against the intent defined in advance, and provenance makes untrusted origin visible to policies. Limitation: ACS does not itself detect prompt injection — its effect depends entirely on policies and an optional classification in the Guardian. steps/userMessagesteps/knowledgeRetrievalsteps/toolCallResultsteps/toolCallRequest | ||||||
toolCallRequest is the central enforcement point with all five dispositions; ask covers consequential individual actions. Frameworks must route every action with an external effect through this hook. Limitation: actions that bypass the hook are invisible to the policy; methods outside methods_evaluated are treated as ALLOW-by-default. steps/toolCallRequeststeps/toolCallResultprotocols/MCP/tools/call | ||||||
sessionStart binds identity and policy mode, subagentStart can reject privilege escalation by subagents, and approvers must be authenticated. Limitation: ACS does not prescribe an authentication mechanism and does not issue identities; the identity model has not yet been specified normatively in v0.1. steps/sessionStartsteps/subagentStartsteps/toolCallRequest | ||||||
The AgBOM inventories models, MCP servers, tools, skills and other components per session; the Guardian can use deny to stop banned components or a swap at runtime, and skills are bound to their registration via their digest. Limitation: the AgBOM is a self-report by the Observed Agent, and only acs-inspect-dynamic sees runtime changes; marketplace scanning and vulnerability matching are not part of ACS. agbom/snapshotagbom/changedsteps/skillRegistersteps/skillLoad | ||||||
Process and shell execution must go through toolCallRequest and can be controlled there with deny or ask; skillLoad binds executable skill content to verified digests. Limitation: sandboxing and isolation are not part of ACS, and code already running on the host can bypass agent controls. steps/toolCallRequeststeps/skillLoad | ||||||
memoryStore and memoryContextRetrieval control the write and read paths of memory; during compaction, preCompact and postCompact bind provenance to the summary (the union of the lineage of all condensed entries). Provenance lineage is essential here. Limitation: without acs-provenance, provenance information is missing, and ACS does not detect existing poisoned entries on its own. steps/memoryStoresteps/memoryContextRetrievalsteps/knowledgeRetrievalsteps/preCompactsteps/postCompact | ||||||
agentTrigger with trigger_type a2a_inbound, the subagent hooks and the AgBOM type a2a_peer make relationships between agents visible and, to a limited extent, controllable. Limitation: A2A wrapping (protocols/A2A/*) is only reserved in v0.1 and not planned until v0.2, as is AgBOM federation across peers. steps/agentTriggersteps/subagentStartagbom/snapshot | ||||||
The audit chain per session and subagent (final_chain_hash) and trace correlation help to reconstruct how a failure has spread; deny at the tool hooks stops it step by step, and cascading defer decisions must be bounded per session. Limitation: v0.1 has neither a kill switch nor an interrupt, and the fail-open default can itself contribute to a cascade if the Guardian fails. steps/subagentStopsteps/sessionEndsteps/toolCallRequest | ||||||
agentResponse allows deny or modify before delivery; ask gives approvers the question, context and reasoning so that they do not approve blindly. Limitation: large numbers of approval requests cause approval fatigue — the only remedy is a policy design that limits ask to genuinely consequential actions. steps/agentResponsesteps/toolCallRequest | ||||||
deny at every decision-capable hook stops an anomalous agent step by step, sessionStart can reject known agent IDs, and trace provides the basis for anomaly detection in the SOC. Limitation: v0.1 has no dedicated kill switch, and ACS does not itself detect deviant behaviour — that is the job of policies and monitoring. steps/sessionStartsteps/turnStartsteps/toolCallRequest | ||||||
VamiSec assessment based on ACS v0.1.0 — not an official OWASP mapping. ACS does not appear in the OWASP Agentic Top 10 (December 2025), and neither OWASP nor the ACS project has mapped ACS to ASI01 to ASI10; the effect of each cell depends on your policies and the negotiated profiles.
Interactive
Profile navigator: which ACS building blocks fit your agent?
Up to five questions on tools, regulation, data sources, dynamic components and SOC. The result names the ACS profiles and first steps we recommend for your situation — a VamiSec assessment, not a statement of conformance.
Your path
- 1?
1: Does your agent call tools or trigger actions with external effects — files, shell, APIs, emails, tickets, payments?
1
Does your agent call tools or trigger actions with external effects — files, shell, APIs, emails, tickets, payments?
ACS requires steps/toolCallRequest to fire for every action that leaves the reasoning context. Without such actions, inputs and outputs remain the main control points.
Assistant without tools: ACS-Core as the baseline, with a focus on inputs and outputs
Without tool calls, ACS offers limited leverage — there is no action a Guardian would need to stop before execution. The hooks for user inputs and responses remain relevant. Even so, design the architecture so that a Guardian can be plugged in as soon as tools are added (VamiSec assessment).
- Record agents, models and data sources in a register — as a precursor to an AgBOM.
- Use steps/userMessage and steps/agentResponse for redactions via modify, for example of personal data or secrets.
- Check the transparency obligation under Art. 50 AI Act (applicable since 2 August 2026) if the assistant interacts with people.
- Run through the navigator again for every planned tool integration.
acs-coresteps/userMessagesteps/agentResponsemodify
Tool-using agent: ACS-Core with policies on steps/toolCallRequest
For agents with external effects, steps/toolCallRequest is the central control point. Start with ACS-Core and a deterministic policy that selectively blocks, rewrites or submits high-consequence capabilities for approval. Check in the handshake which methods the Guardian actually evaluates — everything else runs unchecked.
- Classify capabilities (e.g. filesystem.delete, network.egress, process.execute) and define allow, deny, modify or ask for each class.
- For sessions with high-consequence capabilities, set on_decision_failure to deny and the startup posture to refuse — the posture applies per session, not per action.
- Compare methods_evaluated in the ServerHello against the list of implemented methods.
- Use ask only with an authenticated approver and timeout_disposition deny.
- Version your policies and run them against test cases before every rollout.
acs-coresteps/toolCallRequeston_decision_failureOPA/Rego
Untrusted content and memory: make provenance mandatory
As soon as web content, emails or RAG results enter the context, checking individual tool calls is not enough. With acs-provenance, every data-bearing field carries its origin; the Guardian can block actions whose arguments come from untrusted sources. ACS does not prevent prompt injection — it creates the control point at which policies counter its consequences. With subagents or skills, add acs-inspect-dynamic; with a SOC, add acs-trace.
- Implement provenance_producer: deterministic in the framework and enable policy_requires_provenance in the Guardian.
- Evaluate steps/toolCallResult and steps/knowledgeRetrieval on ingress and steps/memoryStore before anything is written to memory; use steps/preCompact to keep provenance from being blurred.
- A session rule modelled on Meta’s Agents Rule of Two: once a session has processed untrusted content and has access to sensitive data, actions with external effects only run via ask (VamiSec interpretation).
- Choose a policy paradigm: FIDES, CaMeL and AARM require provenance, pure IBAC does not.
- Test effectiveness with adaptive red teaming rather than static test prompts.
acs-provenancesteps/memoryStorederived_fromFIDES · CaMeL · AARM
Multi-agent, skills and dynamic components: keep the inventory continuously up to date
When subagents are spawned, skills are loaded on demand or MCP servers are bound at runtime, the Guardian needs an up-to-date picture of what the agent is at any given moment. acs-inspect provides the AgBOM snapshot per session; only acs-inspect-dynamic makes changes during the session visible. v0.1 does not yet wrap agent-to-agent communication via A2A.
- Enable agbom/snapshot and agbom/changed; stop hot swaps and unvetted versions via deny.
- Use steps/skillRegister as a static checkpoint and steps/skillLoad with binding to skill_id and digest.
- Evaluate steps/subagentStart: the Guardian can reject spawns whose derived capabilities are not authorised by the parent’s intent.
- Maintain allowlists for models, MCP servers and skills — which can also serve as a supplier register.
- For now, capture A2A peers via steps/agentTrigger (a2a_inbound) and the AgBOM; A2A wrapping will follow with v0.2 at the earliest.
acs-inspectacs-inspect-dynamicsteps/skillLoadAgBOM
SOC in place: feed trace data into the SIEM and monitor the Guardian itself
With acs-trace, hooks and decisions become OpenTelemetry spans and OCSF events — decisions other than allow become a Detection Finding with severity. Build parsers and use cases against the JSON mappings and test them with real data, because some class and field names deviate from OCSF. Trace is self-reported and best-effort, so on its own it is not evidence.
- Use case “Guardian bypass”: alert on every fail-open pass-through and every session started without protection.
- Measure the decision failure rate directly on the hook path — a successful system/ping does not prove that enforcement works.
- Analyse clusters of deny decisions per agent, policy and rule_id as an anomaly signal.
- Separate agent identities from human users in OCSF via actor.user.type “AI Agent”.
- Apply redaction at the point of emission — spans can contain prompts and tool arguments.
acs-traceOCSF 2004OpenTelemetrySIEM
Regulated use: combine evidence-ready profiles and operate fail-closed
If your case rests on the AI Act, DORA or NIS2, you need more than ACS-Core: Core contains neither Trace nor the binding of the audit chain to request contents. ACS supports evidence gathering but does not establish a presumption of conformity. Depending on the architecture, add acs-provenance and acs-inspect-dynamic. The mapping to legal provisions is a VamiSec interpretation and is no substitute for a legal review.
- Require acs-trace and acs-audit (request_hash), and additionally acs-crypto with ML-DSA-65 for non-repudiation.
- Configure on_decision_failure: deny and the startup posture refuse, and demonstrate both through testing.
- For Art. 14 AI Act: use ask on steps/toolCallRequest only with approver.type human and timeout_disposition deny; v0.1 has no stop button, only step-by-step deny.
- Define retention in the SIEM or archive — ACS sets no retention periods; Articles 19 and 26 AI Act require at least six months for high-risk logs, subject to other applicable law.
- In the financial sector, build your case on DORA and Delegated Regulation (EU) 2024/1774, Art. 12.
acs-traceacs-auditacs-cryptoArt. 14 AI ActDORA
- Does your agent call tools or trigger actions with external effects — files, shell, APIs, emails, tickets, payments?
- Do you deploy the agent in a regulated context with evidence obligations — for example as a high-risk system under the AI Act, in the financial sector under DORA or as a NIS2 entity?
- Does the agent process untrusted content — web pages, emails, tickets, RAG results — or write to long-term memory?
- Does the agent start subagents, load skills or bind MCP servers and models at runtime?
- Do you run a SOC or SIEM that should analyse agent events and raise alerts?
Deep dive · 14 chapters
The Agent Control Standard in detail: from the control problem to operations
Fourteen chapters for CISOs, security architects and AI platform owners: what specification v0.1.0 normatively requires, where it currently stops and which decisions need to be made before adoption. Mappings to incidents, risks and regulation are marked as VamiSec assessment.
Why AI agents need runtime control
An AI agent does not just answer questions; it triggers actions — in file systems, databases, mailboxes and cloud accounts. The security question therefore shifts from model output to who checks a specific action before it is executed.
From answer generator to actor
Classic LLM applications generate text that a human reads before anything happens. AI agents, by contrast, plan autonomously, call tools, write to long-term memory and spawn subagents. Each of these steps can change data or send it outside. The control question is therefore: “May exactly this action, with exactly these arguments, take place in this session right now?” It can only be answered at runtime — between the model’s decision and its execution by the framework.
System prompts are not controls
Many deployments rely on system-prompt instructions such as “do not delete production data”. Such sentences are requests to a probabilistic system, not enforced rules. The ACS project page opens its rationale on exactly this point: system prompts are not controls, better models do not cover edge cases and adversarial inputs, and proprietary guardrails create vendor lock-in.
Vendors and researchers confirm this. On 22 December 2025, OpenAI wrote that prompt injection is “unlikely to ever be fully ‘solved’”. In the study “The Attacker Moves Second” (arXiv, 10 October 2025), adaptive attacks overcame twelve recent defences, mostly with success rates above 90 per cent — even though most of them had originally reported rates close to zero. Model robustness lowers the risk but does not eliminate it. What is needed is an independent control point outside the model.
Lethal trifecta and the Agents Rule of Two
On 16 June 2025, Simon Willison described the “lethal trifecta”: an agent that has access to private data, is exposed to untrusted content and can communicate externally can be manipulated via prompt injection into exfiltrating data. On 31 October 2025, Meta extended this into the “Agents Rule of Two”: within a session, an agent should combine at most two of three properties: processing untrusted inputs; accessing sensitive systems or private data; changing state or communicating externally. If it needs all three, at least supervision is required, for example through human approval. Meta stresses that the rule complements least privilege rather than replacing it.
VamiSec assessment: both models describe properties of a session, not of a model. They can only be enforced if one component sees every action and the session history so far. This is the control point that the OWASP Agent Control Standard (ACS) standardises. Detecting untrusted inputs requires the optional acs-provenance profile; ACS-Core alone does not provide provenance information.
Documented incidents — and what runtime control could have limited
| Incident (source, date) | What happened | Could have limited it (VamiSec assessment) |
|---|---|---|
| EchoLeak, CVE-2025-32711, Microsoft 365 Copilot (NVD 11 June 2025; CVSS 3.1: 9.3 Microsoft, 7.5 NVD) | Zero-click: a crafted email caused Copilot to leak internal data via the rendered response; fixed before disclosure. | Inspection of steps/agentResponse with modify (stripping external image and link URLs) or deny — provided the host fires the hook and supplies provenance. |
| Replit agent deletes production database (SaaStr, July 2025; The Register 22 July 2025) | The agent ignored an instructed code freeze, deleted the production database and generated misleading status messages. | deny or ask on destructive database capabilities at steps/toolCallRequest; audit chain for reconstruction. Primarily: dev/prod separation, backups. |
| GitHub MCP “Toxic Agent Flow” (Invariant Labs, 26 May 2025) | Prompt injection in a public issue; the agent published data from private repositories via a pull request. No code flaw in the server, no CVE. | Session policy “no writes to another repository after untrusted tool output” with deny or ask at steps/toolCallRequest; requires acs-provenance. |
| Amazon Q Developer Extension v1.84.0, CVE-2025-8217 (AWS-2025-015, 23 July 2025; CVSS 4.0: 5.1) | Injected deletion prompt in the official release; execution failed because of a syntax error, and customer resources were not affected. | The prompt came from the product itself and counts as trusted — provenance does not help. Effective measures would have been deny or ask on deletion capabilities and version pinning via the AgBOM. |
| ClawHavoc: malicious skills on ClawHub (The Hacker News 2 February 2026; Unit 42 23 June 2026) | An initial audit found 341 malicious skills among 2,857 reviewed, including some with a Base64-encoded dropper. | Inspection at skillRegister and digest binding at skillLoad; then deny on download-and-execute (network.egress plus process.execute). |
All incidents predate the canonical ACS specification v0.1.0 (5 June 2026). The right-hand column is an assessment, not a claim that ACS would have prevented an incident.
Why control has to sit at runtime
Model selection, prompt hardening and red teaming before go-live remain necessary, but they do not tell you what an agent does in a specific session. Runtime control complements them: it acts before the action, evaluates the context of the entire session and leaves a reconstructable audit trail. For ASI02 (Tool Misuse and Exploitation), the OWASP Top 10 for Agentic Applications 2026 recommends upstream policy enforcement middleware, an “Intent Gate” that checks intent and arguments before execution. ACS is not mentioned there, but (VamiSec assessment) it provides an open wire contract for precisely this control point. The policies remain your responsibility.
What ACS is: parties, three pillars, ACS-Core and seven profiles
The OWASP Agent Control Standard (ACS) is an open wire specification through which a separate Guardian Agent checks what an AI agent intends to do next. The Guardian allows, blocks or modifies the action, submits it for approval or defers its decision — before the action takes place.
More precisely: the Agent Control Standard (ACS) is a specification of the OWASP GenAI Security Project that defines at which control points (hooks) an AI agent submits its steps to an external policy authority and how that authority responds with a decision (disposition). The format is JSON-RPC 2.0 with a dedicated acs_version field, transported over HTTP(S) or stdio. The current version is specification v0.1.0, published as release 0.1.2 (tag dated 21 September 2026). ACS defines the contract between agent and Guardian, not the policies: what is permitted is still decided by your organisation.
The parties
| Role | Responsibility according to the specification | Typical implementation (example) |
|---|---|---|
| Observed Agent | The monitored, LLM-based system. It implements the wire contract, reports every relevant step via a hook and enforces the disposition it receives. It does not decide on its own actions. | Coding agent, support agent, agent framework with host integration |
| Guardian Agent | The policy authority. It evaluates every hook against the deployment policy, returns a disposition and must log every decision with its reasoning, the evaluator’s model identifier and — where available — confidence. | Policy engine (e.g. OPA/Rego), optionally supplemented by an LLM layer |
| Approver | A third party that the Guardian involves on ask: a human, an agent or a service. The Guardian must verify its identity against the policy. | Security officer, approval service, ticket workflow |
| Principal | The authenticated party that initiates a session or acts within it. | Employee, service account |
The specification requires three identities to be kept separate: that of the Observed Agent, that of the Guardian and that of the policy author.
One design principle underpins the architecture: the language model must know nothing about the hooks. The framework fires them, and provenance information is set outside the model’s output path. As we read it, the intention is that a manipulated model can neither see nor influence the control point.
Three pillars: Instrument, Trace, Inspect
Instrument
Real-time interception, evaluation and enforcement: 19 native steps/* hooks, five dispositions, handshake, replay protection and signatures. The mandatory baseline, ACS-Core, is built on this pillar.
Trace
A vocabulary through which hook events appear as OpenTelemetry spans and OCSF events; decisions are recorded as a span event on the triggering step. ACS does not invent a new log format. Trace runs decoupled from enforcement and is best-effort.
Inspect
The AgBOM (Agent Bill of Materials): a dynamic inventory of models, MCP servers, A2A peers, tools, knowledge sources, memory stores, capabilities and skills, serialisable to CycloneDX 1.6, SPDX 3.0 or SWID.
ACS-Core and seven profiles
Conformance is modular. ACS-Core is the mandatory baseline, on top of which sit six optional profiles that a deployment declares in the handshake. There are no numbered levels — only profile names that can be combined independently. The only dependency: acs-inspect-dynamic extends acs-inspect.
| Profile (handshake name) | Core requirement | What you need it for |
|---|---|---|
| acs-core (mandatory) | Among other things: handshake, JSON-RPC envelope, at least six hooks, all five dispositions with mandatory fields, hash-chained audit chain with a published chain head, replay protection, HMAC-SHA256 signature on every request and every response, Decision Honoring, system/ping | Authenticated channel; the agent follows the Guardian’s decisions |
| acs-trace | For every supported step, OpenTelemetry and/or OCSF events with mandatory attributes; every decision as a trace event | SIEM integration, cross-vendor observability |
| acs-inspect | agbom/snapshot once per session before the first content-bearing hook; on request, the Guardian serialises to at least one BOM format | Policies that depend on the inventory, such as banning a model or tool |
| acs-inspect-dynamic | Additionally, agbom/changed whenever the component graph changes | Detecting hot swaps of models, MCP servers or skills during the session |
| acs-provenance | Provenance object on every data-bearing field of every hook (provenance_producer: deterministic) | Information-flow policies following FIDES, CaMeL or AARM-style patterns |
| acs-crypto | Asymmetric or post-quantum signatures, at least ML-DSA-65 | Non-repudiation towards third parties |
| acs-audit | request_hash on every ContextEntry in the audit chain | The chain also binds request content, not just metadata |
In v0.1.0, conformance is a self-declaration in the handshake: no test suite, no register of conformant implementations, no assessment body.
The specification is matter-of-fact about what ACS-Core guarantees: the channel is authenticated, and the Observed Agent follows the decisions. It does not guarantee that the policies are strict — a permissive Guardian is conformant, just permissive. Tamper evidence for the audit chain, even against a compromised Guardian, is only provided by acs-crypto and acs-audit, because the HMAC baseline is a symmetric scheme. The specification’s example combinations range from a minimal IDE integration with acs-core only to a high-assurance deployment with all seven profiles.
The project page’s tier model: architectural layers, not levels
- 1Tier 1 · Platform layer
Agent frameworks provide standardised middleware hooks — this is where the control point is created.
- 2Tier 2 · Enforcement layer
An open-source component reads declarative policies and returns decisions via these hooks.
- 3Tier 3 · Enterprise layer
Custom classifiers and domain-specific logic plug in behind the same interface.
This model describes who contributes which part, not how conformant a deployment is. For conformance claims, only the profiles count. It is still useful for your architecture planning: it separates the question of which platform supplies the hooks from the question of who operates and maintains the policies.
Origins, governance and licensing: from AOS to an OWASP project
Anyone adopting a standard early should know who steers it, which licence it is under and how reliable its roadmap is. ACS has a short but eventful history.
From observation to control
Work began on 11 May 2025 as the “Agent Observability Standard” (AOS) in Zenity’s GitHub environment and moved to the OWASP organisation in June 2025, where AOS was listed as an “OWASP other project”. In May and June 2025, the protocol layer was temporarily called “ASOP” (Agent Security & Observability Protocol) before reverting to AOS. After a phase with only sporadic commits from mid-2025, the rebranding to Agent Control Standard followed on 10 April 2026. The new name marks the substantive step from mere observation to enforcement. ACS then briefly ran as an independent project outside OWASP and returned in September 2026 — this time to the OWASP GenAI Security Project.
| Date | Milestone |
|---|---|
| 11 May 2025 | First commits as “Agent Observability Standard” (AOS) |
| June 2025 | Transition to the OWASP organisation |
| 10 April 2026 | Rebranding AOS → ACS (Agent Control Standard) |
| 27 May 2026 | Launch press release via Business Wire; phase as an independent project |
| 5 June 2026 | Canonical specification v0.1.0 integrated, including the skill hooks |
| 11 August 2026 | Release v0.1.1: new licensing, specification unchanged |
| 1–10 September 2026 | OWASP relaunch: resource page (1 September), site and 44 JSON schemas (5 September), governance and reference implementation (10 September) |
| 21 September 2026 | Tag v0.1.2, set retroactively on a commit from 9 September 2026 |
| March 2027 (target) | Next specification release v0.2.0 |
Sources: Git history and project documents of the ACS repository and the OWASP resource page, as of 3 October 2026.
Status: Incubator and public preview
ACS is a project of the OWASP GenAI Security Project, where it is assigned to the Agentic Security Initiative. In its own OWASP Nest metadata it declares Level 2 — the “Incubator” stage in the Nest schema; this does not establish a classification by an OWASP body. The project lead publicly describes the status as “public preview” and explicitly advises implementers to proceed with caution. ACS is not an ISO, IETF or W3C standard and not a harmonised standard. The early stage is also evident formally: there are no GitHub releases, only tags; specification prose and schemas changed between v0.1.1 and v0.1.2 without the specification version v0.1.0 being incremented.
Who steers the project?
According to GOVERNANCE.md, Michael Bargury and Ory Segal created ACS; both remain project leaders. The project lead is Rock Lambros. For transparency: Bargury is CTO and co-founder of Zenity, Lambros is listed by Zenity as “Director of AI Standards and Governance”, and the early AOS commits come predominantly from the Zenity sphere. The workstreams — Coding Agents, Development (SDK), Identity, Outreach and Spec — are led by people from several organisations. The project page describes ACS as vendor-neutral and community-governed; that is a self-description. Our assessment: an OWASP project with a strong Zenity imprint in its founding and leadership.
Decisions go through an acceptance gate. Only issues labelled status:accepted make it into the backlog; changes to behaviour, normative text or code require an accepted issue, specification changes start as a GitHub Discussion, and commits require a DCO sign-off. Development takes place on the integration branch. Only when the project lead promotes to main are the site and schema URIs republished. As of 3 October 2026, main has not been promoted since 10 September 2026 — changes on integration are therefore not yet published.
Licensing: what you may reuse
| Component | Licence | Practical consequence |
|---|---|---|
| Code, JSON schemas, code examples in the documentation | Apache-2.0 | Use in proprietary products without disclosure obligations; explicit patent licence |
| Prose documentation (specification texts, README) | CC BY-SA 4.0 | Translations and adaptations are subject to ShareAlike and require attribution |
| Releases up to and including v0.1.0 | MIT | The licence granted at the time remains in force |
| Names and logos (OWASP, Agent Control Standard) | no rights granted | An implementation may describe itself as “ACS-conformant” but must not suggest endorsement by the project |
The relicensing to Apache-2.0 and CC BY-SA 4.0 took effect with release v0.1.1 on 11 August 2026. VamiSec writes all content on this page independently and does not translate any specification prose.
Roadmap: what is documented
The next specification release, v0.2.0, is targeted for March 2027; no date has been set for v1.0. Items earmarked for v0.2 include streaming and interruption, recursive ASK and quorum, multi-tenant isolation, the Cedar binding, AgBOM federation across A2A peers and A2A wrapping. The ongoing goal since the kick-off on 10 September 2026: within 90 days, a working Guardian reference implementation, benchmarked for interoperability with Microsoft’s Agent Governance Toolkit, in the hands of external evaluators. Whether this will be achieved by early December 2026 remains open. Also open is PR #21, which seeks to redraw the mandatory scope of ACS-Core. Diverging version outlines in blog posts are not an official roadmap.
Instrument: the 19 hooks in an agent’s lifecycle
At each hook, the Observed Agent pauses and submits its next step to the Guardian. ACS v0.1.0 defines 19 native steps/* hooks — which of them are actually evaluated is negotiated by both sides per session.
On the wire, hooks carry the prefix steps/, for example steps/toolCallRequest. In addition, there are methods that are not native steps/* hooks: agbom/snapshot and agbom/changed for the inventory, the liveness probe system/ping, the handshake handshake/hello and the protocols/MCP/* namespace for wrapped MCP messages. The specification’s hooks page counts 19 hooks plus two AgBOM methods plus ping as 22 methods; the schema package comprises 44 JSON schemas in total. Some project texts (README, docs/acs.md) still refer to 16 lifecycle hooks — that is the count without the three skill hooks.
| Group | Hooks (steps/…) | When they fire | Dispositions according to the specification |
|---|---|---|---|
| Session | sessionStart, agentTrigger, sessionEnd | After the handshake, before any other step; activation by user, schedule, event, A2A or system; end of the session, at which the Guardian seals the chain | sessionStart: allow/deny · agentTrigger: allow/deny/modify · sessionEnd: audit only |
| Turn | turnStart, turnEnd | Start and end of each agent turn; the turn_id accompanies all steps in between | turnStart: decision-capable, usually allow · turnEnd: audit only |
| Messages | userMessage, agentResponse | User input before it reaches the reasoning context; agent output before delivery | allow/deny/modify |
| Knowledge & memory | knowledgeRetrieval, memoryContextRetrieval, memoryStore | Knowledge and RAG queries, memory reads into the context, writes to long-term memory | allow/deny/modify |
| Tools | toolCallRequest, toolCallResult | After a tool call is parsed and before dispatch; after execution, before the result is accepted | toolCallRequest: all five · toolCallResult: allow/deny/modify |
| Compaction | preCompact, postCompact | Before and after the context window is compacted | preCompact: deny possible · postCompact: modify, no deny |
| Subagents | subagentStart, subagentStop | Start of a subagent in the same process; its termination | subagentStart: deny possible · subagentStop: audit only |
| Skills | skillRegister, skillLoad, skillUnload | Admission to the available set as a static gate; activation in the session; removal | skillRegister and skillLoad: allow/deny · skillUnload: audit only |
The per-hook restrictions are set out in the specification prose; the response schema itself does not restrict the decision field per method.
The core minimum: six hooks
ACS-Core requires at least six hooks: sessionStart, userMessage or agentTrigger, toolCallRequest, toolCallResult, agentResponse and sessionEnd. A framework should implement all the others if it can observe the relevant event; they are negotiated in the handshake. For your product evaluation, this means that the statement “supports ACS” does not yet tell you whether memory writes, subagents or skills reach the Guardian at all.
The methods_evaluated trap
In the handshake, the Observed Agent reports which methods it implements (methods_implemented). The Guardian responds with the list of methods it actually evaluates (methods_evaluated). If the agent sends a hook that is missing from this list, it must treat it as ALLOW-by-default — at best the step is logged, but it is not checked. The only reference implementation, for example, evaluates only steps/toolCallRequest and steps/toolCallResult, i.e. two of 19 hooks.
toolCallRequest: the central enforcement point
steps/toolCallRequest is the only hook for which the specification explicitly provides all five dispositions; this is also where the control paradigms apply. One MUST rule is central: frameworks must fire toolCallRequest for every action that leaves the agent’s reasoning context — even if the framework does not treat it internally as a tool. This covers read and write access to the file system, network fetches, process launches and shell commands. Anything that bypasses this hook is invisible to any policy.
Mandatory in the payload are tool.name and arguments, where each argument value can carry its own provenance. Optional additions are an abstract capability such as filesystem.delete or network.egress, the raw_command and an intent. This allows policies to evaluate what an action does rather than which program executes it.
Hooks with a particular protective effect
- memoryStore is the standard sink for influence across sessions and, according to the specification, the point of intervention against memory poisoning (cf. ASI06: Memory & Context Poisoning).
- preCompact and postCompact secure compaction: the summary must carry origin agent_generated and inherit the provenance of all compacted entries so that untrusted content cannot be laundered.
- subagentStart allows the Guardian to refuse the start of a subagent; each subagent receives its own session_id and its own audit chain.
- skillRegister and skillLoad bind skills to a digest: only what was previously approved with an identical skill_id and an identical digest may be loaded; loads that cannot be matched should be rejected.
The five dispositions in detail: allow, deny, modify, ask, defer
The Guardian answers each hook with exactly one disposition. The details — mandatory fields, composition rules, timeouts — determine whether a policy fails safely or lets actions through when something goes wrong.
On the wire, dispositions appear in lowercase in the decision field; the specification prose writes them in capitals (ALLOW, DENY …). In v0.1, every response is of type final — intermediate states (progress) and interruptions (interruption) are only planned for v0.2. Mandatory in every response are type, acs_version, request_id and decision; the request_id mirrors that of the request.
| Disposition | Effect on the Observed Agent | Mandatory fields (schema) | Typical use |
|---|---|---|---|
| allow | The action runs as requested | none; reasoning recommended where user-visible audit trails are expected | Read access within the permitted scope |
| deny | The action is blocked | reasoning | Destructive shell command, egress to an unknown destination |
| modify | The action runs with a modified payload | reasoning, modifications | Limiting a query, redacting personal data in the tool result |
| ask | The agent pauses until approval is given | reasoning, ask_details | Payment, bulk mailing to external recipients |
| defer | The decision is postponed | reasoning, defer_details | Unknown script, missing context |
Optional in every decision: reason_codes, policy_references (policy_id, policy_version, policy_name, rule_id), policy_data, cited_provenance_ids and metadata with evaluator (deterministic, agent or composite).
MODIFY: two mutually exclusive forms
The modifications object comes in two forms. Either modified_content replaces the entire payload — in which case no further edits are allowed. Or the Guardian sends structured edits: redactions (JSON Pointer path plus replacement text, default “[REDACTED]”) and/or parameter_overrides (argument name plus new value). Both may occur together, but their targets must be disjoint: no redaction path may hit the same field as an override, nor a parent or child of it. The specification’s rationale: a fixed order of application would resolve conflicts silently and, depending on the order, re-expose redacted values or overwrite sanitised ones. If a Guardian violates these rules, the Observed Agent must treat the response as a deny.
An example: an agent wants to query a customer table in full. The Guardian responds with modify and an entry in parameter_overrides that limits the query to 500 rows — as in the simulator scenario “Unbounded database query”. Override values appear as raw values in the object, not in a value wrapper.
ASK: approval with clear rules
- ask_details requires an approver with type (human, agent or service) and id, a question and timeout_seconds (at least 1).
- When the timeout expires, timeout_disposition applies; the default value is deny.
- The Guardian must verify the approver’s identity against the policy — approver authentication is mandatory.
- Only one hop: approvers must not themselves return ask. Quorum and recursive approvals have been deferred to v0.2.
- If a client cannot resolve ASK, the Guardian must not send ask. Instead, it falls back to defer with timeout_decision deny or to deny with the reason code approver_unavailable — a silent allow is ruled out.
- Via intent_extension, an approval can extend the permitted capabilities for this_request or for the entire session. According to the specification, this is the only conformant way to change the established intent after the fact.
Important from a regulatory perspective: ASK is not automatically human oversight. The approver can be an agent or a service, and timeout_disposition can be set to allow. Human oversight under EU AI Act Art. 14 applies to high-risk systems from 2 December 2027 (Annex III) and 2 August 2028 (Annex I) respectively; AI agents are not high-risk per se. In VamiSec’s assessment, anyone using ASK as a building block for this needs a policy with approver.type human and timeout_disposition deny, as well as an approval process that avoids decision fatigue. ASK then supports your evidence trail but does not by itself fulfil Art. 14: v0.1 has no stop button, only step-by-step deny.
DEFER: postponing the decision, within limits
defer_details requires a reason (insufficient_context, conflicting_policies, low_confidence or pending_dependency), a resolution_method (additional_context, human_approval or timeout) and resolution_timeout_ms. On expiry, timeout_decision only allows deny or ask — no allow — and defaults to deny. The prose requires the field, but the schema does not list it as mandatory; so always set it explicitly. Cascading deferrals must be limited per session. Mind the units: ASK counts in seconds (timeout_seconds), DEFER in milliseconds (resolution_timeout_ms).
Handshake, failure posture and timeouts
Before the first hook fires, the Observed Agent and the Guardian negotiate what is checked, how long to wait and what happens in the event of an outage. These few fields determine whether your control point holds when it matters.
Every session starts with handshake/hello. The ClientHello is carried in the payload of a normal request envelope; the ServerHello comes back as result — without a decision. The negotiated version must match the client’s major version; unknown fields must be ignored.
| Message | Mandatory fields | Security-relevant optional fields |
|---|---|---|
| ClientHello (Observed Agent) | acs_versions_supported, methods_implemented, transports_supported (http, https, stdio), provenance_producer (deterministic or none) | profiles_supported, wrapped_protocols, max_payload_size_bytes |
| ServerHello (Guardian) | negotiated_version, methods_evaluated, selected_transport, timeout_config (default_ms, optional per_method_ms) | on_decision_failure (proceed or deny, default proceed), signature_algorithms_supported, skew_window_ms (default 300000), policy_requires_provenance, approver_types_supported, profiles_accepted, trace_emission, agbom_serializations_supported |
Rejections in the handshake: UNSUPPORTED_VERSION (-32001) on a version conflict; PROVENANCE_REQUIRED (-32002) if the client does not supply provenance but the Guardian policy requires it.
Failure posture: fail-open is the default
For every reported step, the Observed Agent must wait for the decision — up to the negotiated timeout — and apply it. A framework that sends hooks but ignores the verdict is not conformant. If no usable decision arrives, the specification speaks of a decision failure: the Guardian is silent, the transport fails (refused connection, TLS error, malformed response) or the Guardian returns an error instead of a decision. In all three cases on_decision_failure applies, and its default value is proceed: the action continues unchecked. Fail-closed (deny) has to be configured explicitly by a deployment.
The specification is open about the price: anyone who can disrupt the channel turns control into mere logging. As a counterweight, a hard obligation applies — every step that proceeds without a decision must be recorded as an audit event. If a decision does arrive within the timeout after all, the agent must follow it, regardless of the posture.
Startup posture: when even the handshake fails
If the Guardian is unreachable at session start or responds without a ServerHello, a startup posture configured outside the protocol applies: proceed (the session starts unprotected) or refuse. Here, too, proceed is the default so that a Guardian outage does not block new sessions. A session started without protection must be recorded in the deployment’s own audit log. An explicit rejection by the Guardian, such as SESSION_REFUSED, by contrast counts as a decision and not as an outage.
| Situation | Applicable mechanism | Default |
|---|---|---|
| Guardian unreachable at session start | Startup posture (configured outside the protocol) | proceed — session runs unprotected, audit obligation |
| Guardian silent, transport error or error response during the session | on_decision_failure from the ServerHello | proceed — step runs unchecked, audit obligation |
| ASK timeout expires | timeout_disposition | deny |
| DEFER timeout expires | timeout_decision | deny |
| Invalid modifications object | Composition rule for MODIFY | Treated as deny |
| system/ping fails | Transport-level signal, not an enforcement event | no disposition |
Timeouts: no default in the specification
The specification does not set a numerical default timeout. timeout_config.default_ms is mandatory in the ServerHello, but the value is up to the deployment; per_method_ms allows different values per method. The handshake schema points out that every millisecond of timeout can, in the worst case, mean added latency for the step, and recommends aligning per-method timeouts with latency tolerance rather than with a generous blanket value. The reference implementation uses 5000 ms — an implementation value, not a requirement. A sensitivity-based timeout model is planned for v0.2. To clarify terminology: ACS_ON_DECISION_FAILURE is an environment variable of the reference Guardian that sets the value of on_decision_failure — not a field of the specification.
Ping does not prove enforcement
system/ping is a pure liveness probe: the Guardian must always respond with allow, the ping requires no signature and is not written to the audit chain. So a Guardian can answer pings while rejecting every signed hook. The specification therefore recommends monitoring decision failures directly on the hook path.
Guardian architecture: deterministic first, LLM optional
A Guardian Agent is not a second language model looking over the first one’s shoulder. ACS prescribes a fixed order: deterministic policy code decides first; an LLM may only contribute downstream and without visibility into the policy.
Two layers, fixed order
The deterministic layer evaluates every hook first. It either decides itself or delegates to the agent layer — according to the specification, controlled via a chain configuration with the modes “*”, on_ask or pattern-based. However, v0.1 does not define a format for this configuration. The agent layer receives the same inputs plus the interim result of the deterministic layer, but never the policy code. On the way back, its response must pass through the deterministic layer again.
- 1Hook arrives
The request envelope, SessionContext, intent and, if present, provenance are passed to the policy engine.
- 2Deterministic evaluation
Policy-as-code — in v0.1 with OPA/Rego as the starting reference — returns allow, deny, modify, ask or defer, or delegates.
- 3Optional LLM layer
Evaluates cases that cannot be decided deterministically; treats untrusted fields as data and sees no policy code.
- 4Re-check and response
The result passes through the deterministic layer again; metadata.evaluator indicates deterministic, agent or composite.
- 5Logging
Every decision is logged with its reasoning, model identifier and, where available, confidence.
Policy engine: an interface, not a product
ACS defines the interface to the deterministic engine, not the engine itself. The input consists of the request envelope, SessionContext, intent and provenance; the output is a decision envelope, optionally with a delegation to the agent layer (delegate_to). ACS also sets conventions, including: no external HTTP calls in canonical policies. This supports determinism and low latency.
| Engine | Status in ACS | Context |
|---|---|---|
| OPA / Rego | Starting reference for v0.1 | CNCF project with Graduated status (since 29 January 2021), Apache-2.0; the reference implementation uses the OPA bundled with the Agent Governance Toolkit |
| Cedar | Fast-follow for v0.2 (Cedar binding) | Policy language from AWS, Apache-2.0, CNCF Sandbox (since 8 October 2025); basis of Policy in Amazon Bedrock AgentCore |
| Custom engine | Permitted if it adheres to the interface | For example, domain-specific logic or classifiers behind the same interface |
The README and section 2 of the specification mention Cedar and Rego in the same breath; section 12.1 defines the status per version.
Obligations of the LLM layer
- Untrusted data is data, not instructions; the relevant fields must be wrapped or quoted in the prompt.
- No access to the policy code of the deterministic layer.
- Log every decision with reasoning, model identifier and confidence (where available); for evaluator agent or composite, model_id must be specified.
- Timeouts follow the timeout_config negotiated in the handshake.
- The entire layer is optional in v0.1.0: purely deterministic deployments are fully conformant.
Control paradigms without a dedicated wire extension
The specification names four paradigms as targets for v0.1. A Guardian expresses them via the same fields — reason_codes, policy_references, policy_data and cited_provenance_ids. If a deployment combines several paradigms, a single decision may cite all of them.
IBAC · intent-based authorisation
The intent of a session is fixed before untrusted data flows in; after that, it can only be extended via an audited approval (intent_extension). A deviation can end in a defer; policy_data then names the requested capability and the closest entry from Intent.parsed. Works without acs-provenance.
FIDES · information flow control
Research approach with confidentiality and integrity labels (arXiv 2505.23643, 2025). A denial cites the violating lineage in cited_provenance_ids and the affected argument path in policy_data.
CaMeL · program synthesis
Research approach that derives control and data flow from the trusted request (arXiv 2503.18813, 2025). The Guardian checks whether arguments originate from untrusted sources.
AARM-style · cumulative context
Evaluates the session history so far rather than the individual step. A denial cites the earliest untrusted step and reproduces the relevant look-back in policy_data.
FIDES, CaMeL and AARM-style rules need provenance information and therefore require the acs-provenance profile; pure IBAC does not. ACS does not implement any of these approaches itself; it provides the fields through which a Guardian applies and justifies them. In other words, ACS does not prevent prompt injection — it creates the control point at which policies counter its consequences.
Operations: latency and availability (VamiSec assessment)
- Latency: every check sits in the agent’s critical path. Keep the deterministic layer local and free of external calls, reserve the LLM layer for a small number of ambiguous cases and measure evaluation_duration_ms per method.
- Availability: with fail-closed, the Guardian becomes business-critical. Run it close to the agent and redundantly. The reference implementation itself documents the risk: it writes logs synchronously in the decision path, so a slow disk blocks every pending decision.
- Policy lifecycle: version your policies and return policy_version in every decision; the specification provides for this so that historical policy states can be reconstructed.
- Scope: the Guardian is no substitute for a sandbox, IAM, secrets management or an egress firewall. Actions that bypass toolCallRequest remain invisible to it.
The only reference implementation runs Microsoft’s Agent Governance Toolkit unmodified behind the ACS wire. It is explicitly a proof of concept: two of 19 hooks live, no HMAC signature, fail-open by default. It demonstrates the pattern for two clients (Claude Code and OpenCode) but is not intended for production use.
Channel security: signatures, replay protection and the audit chain
A Guardian Agent is only as trustworthy as the channel over which it makes its decisions. ACS-Core therefore requires three mechanisms: a signature on every request and every response, protection against replayed messages, and a hash-linked audit chain. This chapter shows what these mechanisms achieve — and where their limits lie.
Decisions that release or block actions travel between the Observed Agent and the Guardian Agent. Anyone able to tamper with this channel can turn a deny into an allow or replay an old approval. The OWASP Agent Control Standard (ACS) therefore treats channel security as part of the mandatory ACS-Core baseline, not as an optional profile.
Baseline signature: HMAC-SHA256 with a session key
ACS-Core requires a signature over the canonical envelope on every request and every response. The baseline that satisfies this requirement is HMAC-SHA256. The key is derived per session via HKDF — from deployment key material (a pre-shared secret or a channel binding such as a TLS exporter) together with the session_id. v0.1 does not define an in-protocol key exchange. What gets signed is the RFC 8785 canonicalisation (JCS) of the envelope without the signature field; the recipient recomputes this form and rejects any signature that does not match. TLS alone is explicitly not sufficient, because it does not bind individual messages for audit purposes. The only method exempt from the signature requirement is the liveness method system/ping.
Two details matter for the architecture. In the JSON schema, signature is optional, yet it is normatively mandatory in ACS-Core — schema validation alone will therefore not detect missing signatures. And the specification does not fix the salt, info string, hash function or key length for HKDF, so two implementations may derive different keys. In our assessment, these parameters belong in the interface agreement between platform operations and Guardian operations.
Replay protection
Every request carries a request_id (UUID), a timestamp and, optionally, a nonce. The Guardian must reject requests whose timestamp falls outside the negotiated skew_window_ms window (recommended default 300,000 ms, i.e. five minutes) and must reject duplicate request_id values within a session; it should reject duplicate nonces. This implies an easily overlooked operational requirement: synchronised clocks on both sides.
| Code | Name | Trigger | Observed Agent response per the spec |
|---|---|---|---|
| -32000 | SESSION_REFUSED | Policy refuses the session and no more specific code applies (e.g. an impermissible agent_id) | No retry without a policy or configuration change |
| -32001 | UNSUPPORTED_VERSION | No common acs_version in the handshake | Repeat the handshake with a supported version |
| -32002 | PROVENANCE_REQUIRED | Policy requires provenance, but the client reports provenance_producer: none | Reconnect as a deterministic producer or use a Guardian without a provenance requirement |
| -32003 | CAPABILITY_NOT_NEGOTIATED | A method or profile is used that the handshake did not negotiate | Renegotiate the method or profile |
| -32004 | SIGNATURE_INVALID | Mandatory signature is missing, malformed or unverifiable | Re-sign; re-resolve key_id if necessary |
| -32005 | REPLAY_DETECTED | Duplicate request_id or nonce within the session | Generate a new request_id and nonce |
| -32006 | TIMESTAMP_OUT_OF_WINDOW | Timestamp outside skew_window_ms | Correct the clock drift |
| -32007 | CHAIN_MISMATCH | The client’s chain_hash differs from the Guardian’s chain head | Reload session state; a persistent mismatch is an integrity event |
Our own summary of the ACS error registry (specification v0.1.0, §17.1). system/ping must not return an ACS-specific error.
Audit chain: a hash chain with a published head
For each session, the Guardian maintains a SessionContext, an append-only chain of ContextEntries. Each entry receives an entry_hash: SHA-256 over the JCS-canonicalised entry without its hash fields, chained to the hash of its predecessor; the first entry has previous_hash null. Other canonicalisations are not permitted in v0.1. Publication is the decisive point: for every content-bearing step, the Guardian must include the current chain_hash in its response, covered by the response signature. The specification states the reason openly: if the Guardian kept the chain head private, it could, for example, remove a deny, recompute the chain from that point onwards and later present a sanitised history. Anyone capturing the traffic can detect a chain that has been rewritten after the fact.
What the chain proves — and what it does not
- The only mandatory fields of a ContextEntry are entry_id, step_id, step_type and entry_hash. The request_hash over the request content is merely recommended (SHOULD) in ACS-Core and only becomes mandatory in the acs-audit profile. Without it, the chain proves that a step took place, but not what was requested.
- The ContextEntry schema has no field for disposition, rationale or approver. ACS records decisions normatively as trace events (acs-trace profile, Chapter 9); only an intent extension writes a dedicated entry containing the approver identity (Chapter 11).
- HMAC is symmetric: the Guardian holds the key and could re-sign a rewritten chain head. The channel is protected against tampering on the network, not against a compromised Guardian.
- Non-repudiation towards third parties only comes with acs-crypto: at least ML-DSA-65 (MUST), SLH-DSA-128s (SHOULD), hybrid schemes optional.
- v0.1 provides no reconciliation across multiple Guardians (issue #18, deferred).
Trace: OpenTelemetry and OCSF in the SOC
With the Trace pillar, agent actions and Guardian decisions land in the existing observability and SIEM stack. ACS does not invent a new format for this; instead, it provides a vocabulary for OpenTelemetry and OCSF. What matters to the SOC is which classes arrive, how reliable they are and where the mapping still has gaps.
The normative contribution of Trace is its vocabulary: span names, attribute keys, event classes and the mapping of dispositions to severity levels. Transport uses OTLP (gRPC or HTTP) to existing backends; the wire namespace trace/* is merely reserved in v0.1.0. The stated goal is for ACS events to fit into SIEM pipelines without special parsers. In the repository, both the OTel and the OCSF extensions carry the status “Working draft”. Trace is the optional acs-trace profile. Anyone claiming it must emit at least one of the two formats with the mandatory attributes for every supported step, record every decision with its disposition, evaluator and — where available — rationale, and carry provenance facts from the hook over to the event.
OpenTelemetry: spans per hook, decisions as span events
The span hierarchy is deterministic: one root span acs.session per session, beneath it one acs.turn per turn and one step span per hook. Decisions are not separate spans but a span event acs.decision on the step span; the verdict and the controlled action thus share the same parent context. The event’s mandatory attributes are acs.decision and acs.evaluator (deterministic, agent or composite). For tool calls, ACS uses the span names gen_ai.tool.call and gen_ai.tool.result. Note: in the OpenTelemetry GenAI semantic conventions (status “Development” as of October 2026), gen_ai.tool.call is only an attribute prefix; the recommended span name there is execute_tool {gen_ai.tool.name}. Dashboards and queries aligned with these conventions will therefore not match ACS tool spans without adjustment.
| ACS event | OCSF class (UID) | Note |
|---|---|---|
| sessionStart, sessionEnd, subagentStart, subagentStop | 3002 Authentication | Mapped as logon or logoff respectively |
| userMessage, agentResponse, agentTrigger, turnStart, turnEnd | 6002 Application Lifecycle | ACS calls the class “Application Activity” — in OCSF, that is the name of category 6 |
| toolCallRequest, toolCallResult | 1007 Process Activity | Central source for agent actions |
| knowledgeRetrieval, memoryContextRetrieval, memoryStore, preCompact, postCompact | 6005 Datastore Activity | Compaction uses activity_id 99, generically “Other” in OCSF |
| Decisions deny, modify, ask, defer | 2004 Detection Finding | severity_id: modify 2, ask and defer 3, deny 4; allow is normally informational only (1) |
| agbom/snapshot, agbom/changed | 5001 Device Inventory Info | ACS calls the class “Inventory Info” |
Classes as per the ACS mapping (OCSF 1.5+), class names as per OCSF 1.5.0. Agents appear as actor.user.type “AI Agent”; ACS-specific fields such as reason_codes and policy references are placed in unmapped.acs.
SIEM use cases for agents
| Use case | Data basis | Possible response |
|---|---|---|
| Guardian bypass (fail-open) | Mandatory audit event for every step without a decision; unprotected session start | Alert from the very first event for high-risk agents; check Guardian availability |
| Spike in deny decisions | Detection Finding 2004 with severity_id 4, reason_codes, policy_id | Session review; indicator of prompt injection or misconfiguration |
| Approval load | ask findings (severity_id 3) per period, supplemented by approver details from ask_details | Adjust thresholds and approver capacity; prevent approval fatigue |
| Inventory drift | agbom/changed with reason user_action or discovery (only with acs-inspect-dynamic) | Reconcile against the allowlist; tighten the policy if necessary |
| Integrity event | CHAIN_MISMATCH or reason_code chain_mismatch | Investigate as an integrity event; do not dismiss it as a transient error |
| Agent or human | actor.user.type “AI Agent” | Separate baselines; correlation with human identities |
VamiSec interpretation — ACS defines no detection logic and no response playbook. According to issue #37, a conformant format for the fail-open audit event is still missing; build rules against the JSON mappings and test them with real data.
Limitations you should plan for
- Best effort: Trace must never block enforcement. If the sink fails, the decision still reaches the Observed Agent — so telemetry may have gaps.
- Self-reporting: trace events are generated in the observed environment and only become evidence once attested by an external party.
- Skill gap: the mappings cover 16 of the 19 native hooks plus the two agbom methods. skillRegister, skillLoad and skillUnload have neither an OTel nor an OCSF mapping.
- Documentation drift: where provenance is placed in OCSF is contradictory (enrichments in the normative mapping, unmapped.acs.provenance in the guide). The examples page with Splunk and Elastic queries still uses the former name ASOP and OCSF 1.0.
- Data protection: spans may contain prompts and tool arguments. The specification recommends redaction at the point of emission; in our assessment, this should be a binding part of the logging concept.
Inspect: AgBOM — the agent’s runtime inventory
Agents change their capabilities at runtime: a new model, a newly loaded MCP server, a freshly registered skill. The AgBOM (Agent Bill of Materials) makes this state queryable per session and usable for decisions. It is not a new SBOM format — nor does it replace one.
According to the specification, the AgBOM is a queryable, dynamic inventory of the components an Observed Agent uses. The rationale is precise: any policy that depends on what an agent is — which model, which tools — becomes unverifiable without an inventory. If a Guardian policy depends on the inventory, for instance to ban a model or tool, the deployment must implement the acs-inspect profile. The canonical AgBOM is a component graph, stored as a flat list with references by ID so that states can be compared by diff.
Eight component types
| Type | What is captured (selection of mandatory fields) |
|---|---|
| model | Name, version, provider, endpoint and context window; optionally a configuration snapshot |
| mcp_server | Name, version, endpoint and the tools offered |
| a2a_peer | Endpoint and protocol version |
| tool | Name, version, provider and abstract capability, e.g. filesystem.delete or network.egress |
| knowledge_source | Name and source type (vector_db, search_index, knowledge_base, web_search, other) |
| memory_store | Name, scope (session, user, tenant, global) and storage type |
| agent_capability | Name and description of a passive capability group |
| skill | Name, description, and the reference and integrity digest of the loadable artefact |
The normative source is the component.json schema. Some documentation pages mention six or seven types; eight is authoritative.
snapshot and changed: two wire methods
The Observed Agent sends agbom/snapshot once per session, after sessionStart and before the first content-bearing hook; the message contains the complete AgBOM. agbom/changed reports mutations — added, removed or modified components, either as a diff or as a full snapshot — and can carry a cause such as component_upgraded, discovery or user_action. Both events are recorded in the audit chain. The Guardian may use deny to refuse a session with a banned component or to block a hot swap.
Important for choosing profiles: anyone claiming only acs-inspect delivers exactly one snapshot per session and does not track changes. Runtime changes only become visible with acs-inspect-dynamic. The snapshot triggers renegotiation and policy_request refer to mechanisms that are not due to be specified until v0.2 — in v0.1, only session_start can be relied on in practice. Each component should also carry a registration_provenance (mandatory under acs-provenance). This makes it possible to distinguish whether a component comes from the configuration or was added at runtime.
Serialisations: CycloneDX, SPDX, SWID
The canonical form is always what goes on the wire; the Guardian renders serialisations on request for downstream tools. An acs-inspect deployment must offer at least one of them: CycloneDX 1.6, SPDX 3.0 or SWID (ISO/IEC 19770-2). All three mappings have the status “Working draft”, and the mappings to CycloneDX and SPDX are partly not schema-valid. The CycloneDX mapping uses type names such as ai-model or service as component types that CycloneDX 1.6 does not define in that form; the SPDX mapping uses classes and relationships that do not exist in SPDX 3.0.1. Plan exports with your own validation accordingly. CycloneDX itself has been available in version 1.7 since October 2025.
Telling them apart: AgBOM, AI-SBOM, CRA SBOM
AgBOM (ACS)
Runtime-oriented and per session, anchored in the audit chain and usable for decisions. It inventories what the Observed Agent, by its own account, uses in this session; under acs-provenance, it additionally records the origin of each registration.
AI-SBOM / ML-BOM
Describes models and datasets, for example with the CycloneDX ML-BOM or the AI profile of SPDX 3.0. The term AI-BOM does not appear in ACS; the comparison is our own classification.
CRA SBOM
Mandatory from 11 December 2027 for manufacturers of products with digital elements (Annex I, Part II, point 1 CRA): machine-readable, covering at least the top-level dependencies. The AgBOM can supplement this build-time SBOM with runtime components, but it does not replace it.
Provenance and identity: where data comes from, where identity stops
Whether an action is permissible often depends on where the data triggering it comes from. Provenance gives the Guardian these origin facts at field level, and Session Intent locks in the purpose. The identity part of ACS, by contrast, so far mainly describes open questions.
Field provenance: facts instead of trust labels
Provenance answers where a data element came from and how it got to where it is. A provenance object carries a provenance_id, an origin with one of seven values — user_input, system, tool_output, retrieved, agent_generated, a2a_inbound, external — and, optionally, a source_id (such as a tool name, URL or path) and derived_from as a list of predecessors. This information is attached to data-bearing fields, and for toolCallRequest even to each individual argument. A policy can therefore target a specific data flow rather than the entire call.
- Framework-set: origin, source_id and derived_from are assigned by deterministic code outside the LLM output path. Instructing the LLM to generate provenance is not conformant.
- Transitive lineage: derived data inherits the origin of its inputs, including across summarisation and compaction. A summary of external tool outputs thus remains recognisable as such.
- No trust field: a trust value is only reserved in v0.1, not defined in the schema. The Guardian derives trust from origin and source_id against its policy; untrusted material never becomes trusted through LLM processing (monotonicity rule).
- All or nothing: with provenance_producer: deterministic, every data-bearing field must carry provenance; partial population is not conformant. If the client reports provenance_producer: none although the policy requires provenance, the Guardian rejects the session as early as the handshake with PROVENANCE_REQUIRED.
Provenance is not part of ACS-Core but of the acs-provenance profile. It is a prerequisite for enforcement paradigms such as FIDES, CaMeL and AARM, but not for purely intent-based authorisation (IBAC). ACS does not prevent prompt injection. It creates the control point at which a policy can limit the consequences — for example by blocking an email whose recipient and content originate from an untrusted retrieval result. Sensitivity or IFC labels are not part of the standard; they are the responsibility of the Guardian or the deployment.
Session Intent: the locked-in purpose
In ACS, intent is not a wire format but a governance concept: it binds actions to an authorised purpose — before untrusted data can exert any influence. Intent.parsed, the set of capabilities authorised for the session, is fixed at sessionStart or at the first agentTrigger. After that, neither the LLM nor tool outputs nor data from untrusted channels may change it; if the intent is set at sessionStart, a later agentTrigger with a different intent must be rejected.
The only conformant way to extend it is an intent_extension returned by an approver via the ask flow — with mandatory details on capabilities and scope. With scope this_request, the extension applies only to the current request. With scope session, the Guardian appends the capabilities, writes a ContextEntry of type intent_extension containing the approver identity and keeps the provenance of the extension separate from that of the original intent. Under scope_mode strict, it must not honour any extension that the policy prohibits in strict mode. In our assessment, this is the CISO’s lever against creeping privilege expansion: every extension of scope requires an authenticated approval.
Identity: normatively lean, much still in progress
What applies normatively
ACS does not prescribe an authentication mechanism; the mechanism used is declared in the handshake, and trust schemes such as SPIFFE, OIDC or PKI remain deployment-defined. What is mandatory is the authentication of approvers and the separation of three identities: Observed Agent, Guardian and policy author.
What is not yet binding
The working documents of the identity workstream list five runtime challenges; four are “Pending” and one is “Partially specified”. Wording such as “Required by ACS” for DPoP or RAR is not binding — the project itself makes clear that ACS does not prescribe any mechanism. The identifier model and token lifetimes are only proposals.
How it differs from AIMS
The IETF draft AIMS (draft-klrc-aiagent-auth) covers identity issuance, credential binding and transport authentication. ACS sees itself as complementary: enforcement at runtime rather than issuing identities.
The ACS-Core signature authenticates the channel between Observed Agent and Guardian symmetrically. It is neither authentication of the principal nor non-repudiation — and you should not conflate either of these in your architecture or your evidence.
MCP, A2A and skills: protocols and loadable capabilities
Agents talk to tools via MCP and to other agents via A2A, and they load skills as executable building blocks. ACS v0.1 covers these three surfaces to differing extents: MCP wrapping is specified, A2A is only reserved, and the skill lifecycle has hooks of its own.
MCP wrapping: specified, but whether it is mandatory is unresolved
The namespace protocols/MCP/* is the canonical way to carry MCP messages to the Guardian, for example protocols/MCP/tools/call. The MCP message itself remains unchanged; ACS layers the envelope, the decision contract and the audit chain rules on top. The flow has two stages: the agent submits the wrapped request to the Guardian, enforces its decision, forwards the message to the MCP server after an allow (according to the flow description) and also has the server’s response checked before processing it.
A deployment may consolidate MCP tool calls (tools/call) into the generic hooks steps/toolCallRequest and steps/toolCallResult if tool-level policies are sufficient. Wrapping is intended for cases where the policy needs MCP-specific distinctions: capability negotiation at initialize, server-side prompt templates (prompts/get), resource access (resources/read) and notifications (notifications/*). Irrespective of this, frameworks must fire toolCallRequest for every action that leaves the reasoning context — including built-in file, network or shell operations.
MCP 2026-07-28: the spec prose lags behind
Since 28 July 2026, MCP revision 2026-07-28 has been the current one (as of October 2026). It makes the protocol core stateless, abolishes the initialize handshake and, among other things, deprecates sampling and roots. The ACS namespace protocols/MCP/* is version-neutral; revision 2025-06-18 appears in the specification only as an example. The prose, however, still assumes the older semantics and explicitly names initialize negotiation as a point to be controlled. The specification leaves open whether this affects the wrappers in practice, and we are not aware of any robust analysis. In our assessment, MCP-heavy architectures should plan for the generic tool hooks as their primary control point.
A2A: reserved for v0.2
The namespace protocols/A2A/* is only reserved in v0.1; normative wrapping semantics are planned for v0.2 (target for v0.2.0: March 2027). The A2A pages in the repository date from the AOS era in 2025 and are not schema-compatible. Today, A2A relationships are only visible indirectly: via agentTrigger with trigger_type a2a_inbound and via a2a_peer components in the AgBOM. In-process subagents, on the other hand, are covered by ACS through subagentStart and subagentStop; each subagent gets its own session with its own audit chain, which the parent references via the final_chain_hash without merging the chains.
Skill lifecycle: register, load, unload
| Hook | Purpose | Guardian options |
|---|---|---|
| steps/skillRegister | Static checkpoint: the Guardian sees the entire skill definition before any of its actions runs. The approval applies to the pair (skill_id, digest). | allow or deny; a rejected skill must not become loadable. The Guardian should check declared capabilities against the composed tools and may reject overly broad declarations. |
| steps/skillLoad | Runtime gate for each activation; the load_path makes cascades visible (skill A loads B, B loads C). | allow or deny; it should reject loads that lack an attributable approval, carry a deviating digest or fall outside the declared composed_skills. |
| steps/skillUnload | Keeps the active inventory up to date; may alternatively be folded into agbom/changed. | Audit only; according to the specification, repeated loading and unloading is a signal worth watching. |
Our own summary of the hook descriptions in ACS v0.1.0.
The digest covers the complete loadable artefact, including any bundled model weights or adapters; only the reference and the digest are persisted in the AgBOM, not the content. The Guardian should not rely on a digest_verified reported by the framework but should compare against its own approval. The repository’s design proposal for the skill lifecycle openly states the limitation: the digest binds the registered artefact, not code that a skill loads later — such dynamic loading runs as network.egress or process.execute through the regular tool hooks. Pre-publication marketplace scanning is not part of ACS, and the three skill hooks still lack a trace mapping (Chapter 9).
Conformance and maturity: what v0.1 delivers — and what it does not
ACS is a young OWASP project at an early stage. For architecture and procurement decisions, what counts is therefore the verifiable status: specification v0.1.0, release 0.1.2, a reference implementation that is a proof of concept, and conformance by self-declaration.
0.1.0Specification version; release 0.1.2, tagged on 21 September 2026
2 of 19Hooks that the reference implementation evaluates live
7Conformance profiles; every claim is a self-declaration
03/2027Target for v0.2.0; there is no date for v1.0
ACS is a project of the OWASP GenAI Security Project and, according to its own OWASP Nest metadata, is classified at Level 2 (Incubator); the project lead describes its status as “public preview”. ACS is not an ISO, IETF or W3C standard, nor is it a harmonised standard.
What v0.1 already delivers
Despite its early stage, v0.1 has substance: a shared vocabulary of 19 hooks and five dispositions, 44 published JSON schemas, a clearly described failure posture with an audit requirement for every bypass, and a specification that openly names its own gaps. In our assessment, this is enough to measure vendors against an open, shared yardstick and to design your own control points so that they remain compatible with later versions — but not enough to rely on conformance labels.
Conformance is self-declaration
In the handshake, the Observed Agent declares which profiles it supports (profiles_supported), and the Guardian declares which ones it accepts (profiles_accepted). There are exactly seven profiles: acs-core as the mandatory one, plus acs-trace, acs-inspect, acs-inspect-dynamic, acs-provenance, acs-crypto and acs-audit. There are no tiers or levels. Who verifies conformance claims? The specification answers that itself: in v0.1.0, nobody. There is no test suite, no register of conformant implementations and no body that resolves disputed claims (issue #19, open, priority P1). Moreover, ACS-Core guarantees only two things — an authenticated channel, and that the Observed Agent follows the Guardian’s decisions. It does not guarantee strict policies: even a permissive Guardian is conformant.
Reference implementation: an honest look at where it stands
The only reference implementation is explicitly a proof of concept. It runs Microsoft’s Agent Governance Toolkit (AGT), unmodified, as the policy engine behind the ACS wire, with host integrations for Claude Code and OpenCode. It claims acs-core only in a restricted form (“qualified”) and none of the six optional profiles. There is no interoperability benchmark with AGT yet; producing one is the goal of the 90-day window that began with the kick-off on 10 September 2026. No endorsement of ACS by Microsoft can be inferred from this. Beware the name clash: in the AGT documentation, “ACS” stands for Microsoft’s own “Agent Control Specification” (2 June 2026), the policy language of AGT — not for the OWASP standard.
| ACS-Core requirement | Status of the reference implementation |
|---|---|
| Handshake handshake/hello | Served, but the ServerHello consists of constants; the ClientHello is not read |
| At least six hooks | 2 of 19 evaluated: steps/toolCallRequest and steps/toolCallResult |
| All five dispositions | allow, deny and modify present; ask without ask_details (schema-invalid); defer is never produced |
| chain_hash in responses | The chain is maintained but not published on any response |
| Baseline signature HMAC-SHA256 | Not implemented; wire unauthenticated, protected only by loopback binding (issue #70) |
| Replay protection | Not implemented |
| Decision Honoring, on_decision_failure | Implemented on both hosts; default proceed (fail-open), every bypass is audited (issues #32, #37) |
| system/ping, protocols/MCP/* | Not implemented |
Source: self-description of the reference implementation (reference-implementations/agt/README.md), main branch as of 10 September 2026. The reference implementation was only added to the repository after the tagged release commit 0.1.2.
Open spec gaps with practical relevance
- Default fail-open: on_decision_failure and the startup posture are set to proceed; you must configure fail-closed (deny or refuse respectively) deliberately.
- No stop mechanism: v0.1 has no kill switch; interruption and streaming are planned for v0.2. In v0.1, an agent can only be stopped step by step via deny.
- Mandatory scope in flux: an open proposal (PR #21) would downgrade modify and system/ping to SHOULD.
- Interop gaps (our own analysis): the HKDF parameters, the handshake signature and the input for request_hash are underspecified.
- Documentation drift: some pages still mention 16 instead of 19 hooks, or only three dispositions. The specification and the schemas are normative.
Adoption in practice and regulatory context
ACS is not a compliance tool. It does, however, provide technical building blocks that can help you build evidence for obligations under the AI Act, NIS2, DORA and the CRA, as well as for ISO/IEC 42001 requirements. This chapter maps the building blocks to the requirements and outlines a five-step path to getting started.
Three points of context first. First, ACS does not create a presumption of conformity; the specification text contains no mapping to the AI Act, NIS2, DORA, the CRA or ISO/IEC 42001 — all mappings below are VamiSec interpretations. Second, AI agents are not high-risk systems per se. Following the Digital Omnibus (Regulation (EU) 2026/1744), the high-risk obligations under Chapter III, Sections 1–3 of Regulation (EU) 2024/1689 apply from 2 December 2027 for Annex III and from 2 August 2028 for Annex I; Art. 50 has applied since 2 August 2026. Third, any line of argument depends on the profiles: ACS-Core alone includes neither Trace nor AgBOM nor request_hash.
| Requirement | ACS building block (profile) | Evidence artefact | Caveat |
|---|---|---|---|
| AI Act Art. 12: automatic recording | Trace per step and decision events, audit chain (acs-trace, acs-audit) | SIEM data set, verifiable hash chain | Trace is self-reported; ACS-Core does not include Trace |
| AI Act Art. 14(4)(d): override | ask on toolCallRequest with a human approver and timeout_disposition deny (acs-trace) | Decision events with ask_details, intent_extension entries | Per the spec, the approver may also be an agent or a service — exclude this via policy |
| AI Act Art. 14(4)(e): stop | deny on sessionStart, turnStart, toolCallRequest; on_decision_failure deny, startup posture refuse | Evidence of fail-closed configuration, record of a stop drill | No kill switch in v0.1; default fail-open |
| AI Act Art. 26: oversight, monitoring, logs ≥ 6 months | Authenticated approvers, Guardian as runtime monitor, trace export | Approver role matrix, monitoring report, retention policy | ACS does not govern retention; competence remains an organisational matter |
| AI Act Art. 72: post-market monitoring | Trace metrics, AgBOM (mcp_server, a2a_peer), subagent hooks | PMM section “agent runtime data” | Commission template not due until 2 September 2027 |
| NIS2 Art. 21(2) / § 30 BSIG | Policy-as-code (v0.1: OPA/Rego; Cedar binding planned for v0.2), capability policies, AgBOM with skill digest | Approved policy code, component and supplier register per agent | Marketplace scanning is not part of ACS |
| DORA Art. 8–10, RTS (EU) 2024/1774 Art. 12 | AgBOM as inventory, Trace via OCSF, signed chain head, fail-open audit events, timestamp and skew_window_ms | Extended ICT asset register, logging concept, evidence of time synchronisation | HMAC does not protect against a compromised Guardian |
| CRA Annex I: logging, SBOM | Trace as a product feature, AgBOM export (CycloneDX 1.6, SPDX 3.0) | Build SBOM plus AgBOM export, product documentation | Only for agent products; Annex I applies from 11 December 2027; AgBOM does not replace an SBOM |
| ISO/IEC 42001 A.6.2.6, A.6.2.8, A.7.5, A.10.3 | Trace and audit chain, acs-provenance, AgBOM | Event log concept, provenance evidence, supplier list | 42001 confers no presumption of conformity with the AI Act |
| NIST AI RMF MANAGE 2.4, MEASURE 2.4, GOVERN 1.6 | deny and ask, Trace, AgBOM | Deactivation criteria, monitoring plan, inventory | Voluntary framework |
VamiSec interpretation based on ACS v0.1.0; neither OWASP nor any authority has made this mapping. Banks and insurers should build their case primarily on DORA, because the monitoring obligation under Art. 26(5) AI Act is deemed fulfilled through their financial-sector governance requirements. For financial entities with a simplified ICT risk management framework (Art. 16 DORA), Title III of the RTS applies instead of Art. 12.
Getting started in five steps
- 1InventoryCapture and classify your agents
Capture agents, models, tools, MCP servers and skills, and clarify the AI Act classification for each use case. Outcome: an agent register with risk class, owners and data access.
- 2ArchitectureDefine control points and profiles
Check which hooks your platform actually fires and which ones the Guardian confirms under methods_evaluated in the handshake: everything else is treated as allow-by-default and is unprotected. Choose profiles according to your evidence needs, for example acs-core plus acs-trace and acs-audit for logging obligations.
- 3PolicyExpress policies as code
The deterministic layer runs first (v0.1 reference: OPA/Rego). Write rules for destructive commands, egress and payments, require ask with a human approver and timeout_disposition deny for consequential actions, and reference policy versions in policy_references.
- 4OperationsDecide on and test the failure posture
For agents with high damage potential, set on_decision_failure to deny and the startup posture to refuse. Test Guardian outages, replay and signature errors, and monitor decision failures directly, because a successful ping does not prove healthy enforcement.
- 5EvidenceConnect Trace and maintain evidence
Export OCSF or OpenTelemetry to the SIEM, implement the use cases from Chapter 9 and define retention periods. Secure the chain head externally and verify vendors’ conformance claims through your own tests.
For an in-depth treatment with a 100-day programme, a roles and responsibilities model, metrics and assessment questions for agent platforms, see the CISO whitepaper “Agent Control for CISOs”, which you can request further down this page. VamiSec supports assessment, architecture, policy design and testing as an independent consultancy; VamiSec is not part of the ACS project.
Self-assessment
ACS Readiness Assessment: how mature is your runtime control for AI agents?
18 questions across six dimensions, about 10 minutes. You receive your maturity level, your readiness per ACS building block and your biggest gaps, each with a concrete next step.
0 / 18 questions answered
The four levels
- 0 Not in place
- There is neither a rule nor a technical implementation for this.
- 1 Ad hoc
- Individual teams handle it in their own way, without a requirement and without evidence.
- 2 Defined
- Formally mandated and implemented for the most important agents.
- 3 Enforced & measured
- Technically enforced for all relevant agents and verified with metrics.
Your result
Not all questions have been answered yet — unanswered questions count as “Not in place” in the results.
Readiness per ACS building block
ACS-Coregap0 %
Mandatory baseline: minimum hooks, all five dispositions, Decision Honoring with failure posture, audit chain and HMAC signature.
ACS-Tracegap0 %
Steps and decisions as OpenTelemetry or OCSF events for SIEM and forensics.
ACS-Inspectgap0 %
AgBOM as a runtime inventory per session; runtime changes additionally via acs-inspect-dynamic.
ACS-Provenancegap0 %
Origin and lineage on every data-bearing field as the basis for provenance-based policies.
Oversight & EU AI Actgap0 %
Approvals and records that support evidence gathering in high-risk deployments, for example for Art. 12 and Art. 14 — VamiSec assessment, not a presumption of conformity.
Your biggest gaps
Not all questions have been answered yet — unanswered questions count as “Not in place” in the results.
Your answers never leave your browser. Nothing is stored; a results link contains your answers only in the URL fragment.
Free whitepaper
Agent Control for CISOs — runtime control with the OWASP Agent Control Standard
The practical guide to ACS v0.1.0: what the standard governs, how to introduce the Guardian, policies, trace and AgBOM, how this maps to the AI Act, NIS2 and DORA — and what v0.1 cannot yet deliver.

41 pagesPDF, free of chargeGermanAs of 10/2026
- Ten key messages and a one-page board briefing — with five decisions for executive management
- Reference architecture for the Guardian and policy-as-code, including a failure posture concept and SOC integration
- Regulatory mapping from the AI Act to ISO/IEC 42001 with evidence artefacts — and clearly marked limits
- 100-day programme, maturity model and 20 procurement questions for agent platforms and Guardian vendors
The CISO whitepaper: Agent Control for CISOs
Part I · Understand
Management summary with ten key messages and a one-page board briefing, the control problem of agentic AI illustrated by documented incidents, and ACS at a glance: roles, pillars, profiles, history and governance.
Part II · Implement
Hooks and dispositions with wire examples, Guardian architecture and policy-as-code, failure posture, trace into the SOC, the AgBOM as a runtime inventory, and identity and provenance against the consequences of prompt injection.
Part III · Govern
OWASP Agentic Top 10 × ACS as a heatmap, regulatory mapping to the AI Act, NIS2, DORA, CRA, ISO/IEC 42001 and the NIST AI RMF with evidence artefacts — and an honest assessment of what v0.1 does and does not deliver.
Programme & procurement
Maturity model with operating model, a 100-day implementation programme with deliverables and KPIs, 20 procurement questions for agent platforms and Guardian vendors, and answers to typical objections from the board.
New · ICSPIS 2026 (IEEE)
Test, don’t trust: the evidence that makes ACS controls verifiable
A Guardian decides — but does your telemetry also prove that the execution matched the decision? Our paper accepted at ICSPIS 2026 derives an evidence contract from MAESTRO and STRIDE; the deep dive maps it field by field to ACS hooks, provenance and trace — with a fault matrix, ACS crosswalk and negative tests for your CI.
92.9%Recall with security-relevant bindings (P3)
16.7%Recall with causal tracing only (P2)
50%Recall without decision events (F1)
- ACS crosswalk: attack family → predicate → hook → Guardian response
- Minimum decision receipt fields in policy_data
- Research Edition (English): paper plus ACS Practitioner Brief
Glossary
Glossary: terms of the Agent Control Standard
The key terms from ACS v0.1.0 in quotable short definitions — spec terms are given exactly as in the specification.
20 of 20 terms
- Guardian AgentPolicy Enforcement Point
- The external policy authority in ACS: it evaluates the Observed Agent’s hooks outside the model and responds with a disposition — first via deterministic policy code, optionally supplemented by an LLM layer. Not to be confused with Gartner’s market term “guardian agents”.
- Observed Agent
- The monitored AI system that implements the ACS wire contract, sends hooks at every decision point and enforces the dispositions it receives. It reports, but does not decide on its own actions.
- Hooksteps/*
- A point in an AI agent’s lifecycle at which it pauses and asks the Guardian before acting. ACS v0.1.0 defines 19 native steps/* hooks; ACS-Core requires at least six of them.
- DispositionVerdict
- The Guardian’s response to a hook: allow, deny, modify, ask or defer. Except for allow, a justification in the reasoning field is mandatory.
- Failure Postureon_decision_failure
- The Observed Agent’s behaviour when no usable decision arrives in time. The default is proceed (fail-open); deny (fail-closed) must be configured deliberately, and every pass-through without a decision must be audited.
- Handshakehandshake/hello
- The mandatory session setup via handshake/hello, in which the Observed Agent and Guardian negotiate the version, evaluated methods (methods_evaluated), timeout and failure posture. Methods that are not evaluated are treated as allowed without being checked.
- ACS-Coreacs-core
- The mandatory base profile of every ACS implementation. According to the specification, it ensures two things: an authenticated channel, and that the Observed Agent follows the Guardian’s decisions — it does not guarantee strict policies.
- Conformance profileProfile
- A scope of functionality declared in the handshake: acs-core plus the optional profiles acs-trace, acs-inspect, acs-inspect-dynamic, acs-provenance, acs-crypto and acs-audit. In v0.1.0, this is pure self-declaration without a test suite or assessment body.
- AgBOMAgent Bill of Materials
- The dynamic inventory of an Observed Agent’s components, with eight types from model to skill. It is reported per session, written to the audit chain and can trigger Guardian decisions; it is neither an AI-BOM nor a CRA SBOM.
- Provenance
- Field-level origin information for data in the hook payload: origin, source_id and derived_from. The framework sets it deterministically, never the LLM; it is only mandatory in the acs-provenance profile.
- Audit chainSessionContext
- The append-only chain of a session’s ContextEntries, linked via SHA-256 hashes. The published and signed chain_hash makes subsequent changes detectable — tamper-evident, but not protected against a compromised Guardian.
- Policy-as-Code
- Security rules as versioned, executable code rather than a document. In ACS, this is the Guardian’s deterministic layer, which always runs first; the v0.1 starting reference is OPA/Rego, with Cedar following in v0.2.
- Human-in-the-loop / ASK approverask, approver
- With ask, the Guardian submits an action to an approver for approval. Approvers can be a human, an agent or a service and must be authenticated; human oversight only comes about through a policy with approver.type human and timeout_disposition deny.
- DEFERdefer
- The disposition with which the Guardian postpones a decision, for example due to missing context or low confidence. If the deadline expires, deny applies by default; cascading deferrals must be capped per session.
- MODIFYmodify
- The disposition with which the Guardian permits an action in modified form — via parameter_overrides, redactions or complete replacement content. The Observed Agent must treat a non-compliant modify like deny.
- Session IntentIntent.parsed
- The set of permitted capabilities for a given purpose, defined at the start of a session. It must not be altered by the LLM or by tool outputs, and it can only be extended through audited approval via ask (intent_extension).
- Capability
- An abstract permission such as filesystem.delete, network.egress or process.execute. It describes the effect of an action independently of the specific tool and is the unit in which session intent and policies are expressed.
- MCP wrappingprotocols/MCP/*
- The namespace specified in v0.1 in which ACS forwards MCP messages unchanged to the Guardian. Deployments may alternatively map MCP tool calls via the generic tool hooks; A2A wrapping is only planned for v0.2.
- Reference implementation (AGT)Proof of concept
- The only proof of concept in the ACS repository: a TypeScript Guardian that runs Microsoft’s Agent Governance Toolkit unchanged behind the ACS wire, connected to Claude Code and OpenCode — neither production-ready nor fully ACS-Core-conformant.
- Agent Control Specification (Microsoft)Microsoft ACS
- A separate, Rego-based policy specification from Microsoft for the Agent Governance Toolkit (2 June 2026). It is also abbreviated “ACS”, but is not part of the OWASP Agent Control Standard.
FAQ
Frequently asked questions about the Agent Control Standard
Short answers for CISOs, security architects and GRC — as of 4 October 2026, specification v0.1.0.
The OWASP Agent Control Standard (ACS) is an open wire specification for runtime control of AI agents. It defines how an agent — the Observed Agent — reports relevant steps via hooks to a separate Guardian Agent and waits for its decision: allow, deny, modify, ask or defer. Three pillars complement each other: Instrument for hooks and dispositions, Trace for audit events based on OpenTelemetry and OCSF, and Inspect for the AgBOM. ACS is a project of the OWASP GenAI Security Project, currently at specification v0.1.0, release 0.1.2 (tagged on 21 September 2026). Code and schemas are licensed under Apache-2.0, the documentation under CC BY-SA 4.0.
No. ACS is an early-stage OWASP project — at Level 2 (Incubator) according to its own project metadata, and described by its own project lead as a “public preview”. It is neither an ISO, IETF or W3C standard nor a harmonised standard. In v0.1.0, conformance is a self-declaration that nobody verifies (issue #19). Even the mandatory scope of ACS-Core is still under discussion in an open pull request. The roadmap is provisional, too: v0.2.0 is targeted for March 2027, and v1.0 has no date yet. In the interest of transparency, its origins should also be noted: the project’s founding and leadership have been strongly shaped by Zenity.
System prompts are not controls: they operate in the same channel that an attacker can influence via prompt injection. Guardrail frameworks are concrete implementations, each with its own interface. ACS, by contrast, defines an open, cross-framework interface between the agent host and an external Guardian: the decision is made outside the model, deterministic policies run first, and the agent must enforce the result. This matters because, according to OpenAI, prompt injection is “unlikely to ever be fully ‘solved’” (22 December 2025). ACS does not prevent prompt injection — it creates the standardised control point at which policies counter its consequences.
ACS replaces neither protocol; instead, it adds a control layer on top of them. For MCP, v0.1 specifies the version-neutral namespace protocols/MCP/*: messages are passed unchanged to the Guardian, which evaluates them before they are forwarded or processed. Deployments may alternatively map MCP tool calls via steps/toolCallRequest and steps/toolCallResult; the spec text is contradictory on whether MCP wrapping is part of ACS-Core. The spec prose also still assumes mechanisms that predate the current MCP revision 2026-07-28. In v0.1, A2A is only reserved, and wrapping follows with v0.2. Until then, the options are steps/agentTrigger with a2a_inbound and the AgBOM type a2a_peer.
ACS can support evidence gathering, but it does not in itself satisfy the AI Act and does not establish a presumption of conformity. For the record-keeping obligation under Art. 12, acs-trace (events per step) and acs-audit (a tamper-evident audit chain bound to request contents) provide building blocks. For human oversight under Art. 14, ask is only suitable with a policy of “human approver, timeout deny”; v0.1 has no stop button, only step-by-step deny. Mind the deadlines: under Regulation (EU) 2026/1744, high-risk obligations apply from 2 December 2027 (Annex III) and 2 August 2028 (Annex I) respectively, while Art. 50 has applied since 2 August 2026. AI agents are not high-risk per se. The mapping is a VamiSec interpretation.
By default, the agent carries on. If no usable decision arrives within the negotiated timeout, on_decision_failure applies with the default proceed (fail-open); a failed handshake also starts the session unprotected by default. Every such pass-through must be recorded as an audit event — the spec openly acknowledges that an attacker who disrupts the channel can thereby turn control into mere logging. You achieve fail-closed with on_decision_failure: deny and the startup posture refuse. Expired ask and defer decisions, by contrast, fall back to deny by default. Because the posture applies per session, we recommend separate Guardians or sessions per risk class (VamiSec assessment).
The specification sets no millisecond target. The timeout is negotiated in the handshake (timeout_config.default_ms, optionally per method); in the worst case, every millisecond of it is additional waiting time for the agent. The reference implementation sets 5000 ms. Deterministic policies save latency; according to the spec, they should not contain external HTTP calls. In our assessment, the optional LLM layer costs noticeably more, and according to the spec, signing with SLH-DSA-128s takes several hundred milliseconds. Operationally, we recommend running the Guardian close to the agent and with redundancy, budgeting timeouts per method and monitoring the decision failure rate as a metric — a successful system/ping does not prove that enforcement works.
There is exactly one reference implementation, explicitly a proof of concept: a TypeScript Guardian that runs Microsoft’s Agent Governance Toolkit unchanged behind the ACS wire, with host integrations for Claude Code and OpenCode. It evaluates two of 19 hooks live (steps/toolCallRequest and steps/toolCallResult), signs nothing (issue #70), has no replay protection and runs fail-open by default (issues #32 and #37). The project aims to deliver an interoperability benchmark by early December 2026, but none is available yet. None of this implies support from Microsoft. We are not aware of any substantiated production deployments (as of 4 October 2026).
No — this is a naming trap. On 2 June 2026, Microsoft published its own “Agent Control Specification”, also abbreviated ACS: a Rego-based policy specification of the Agent Governance Toolkit with eight interception points and decisions such as allow, warn, deny and escalate. It comes from Microsoft, not from the OWASP GenAI Security Project, and does not mention the OWASP standard. The connection is indirect: the ACS reference implementation uses the toolkit as its policy engine; the npm package agent-control-specification used there is Microsoft’s SDK, not an artefact of the OWASP standard. On this page, ACS always refers to the OWASP Agent Control Standard.
Treat ACS as a reference architecture, not as a product feature. Start with an agent inventory covering tools, models, MCP servers and skills, and a risk classification, for example along the lines of the lethal trifecta. This is followed by policies for high-consequence capabilities on steps/toolCallRequest, a deliberate decision on failure posture and approvers, and connecting the trace to your SIEM; Chapter 14 describes the five steps in detail. The profile navigator and self-assessment show your starting point, and the whitepaper contains a 100-day programme. Verify vendor claims about ACS profiles through testing rather than taking them at face value. How to prove the effectiveness of your Guardian policies with negative tests and decision receipts in CI is shown in our deep dive “Agentic AI Security Testing” on the ICSPIS 2026 paper. VamiSec provides independent support with assessment, architecture, policy design, implementation and testing.
Standards & Sources
The content on this page is based on the following publicly available guides and studies.
OWASP GenAI Security Project · 2026
Agent Control Standard (ACS) — GitHub repository ↗
Primary source: specification v0.1.0, release 0.1.2, 44 JSON schemas, reference implementation (PoC); code and schemas Apache-2.0, documentation CC BY-SA 4.0 — reviewed as of 3 October 2026
OWASP GenAI Security Project · 2026
ACS Instrument Specification v0.1.0 ↗
Published spec documentation: wire format, handshake, hook taxonomy with 19 hooks, dispositions, failure posture, signatures and error codes
OWASP GenAI Security Project · 2026
ACS Conformance — ACS-Core and profiles ↗
Mandatory scope of ACS-Core, the six optional profiles and the note that nobody verifies conformance claims in v0.1.0
OWASP GenAI Security Project · 2026
ACS JSON Schemas v0.1.0 (example: defer-details.json) ↗
Project-owned schema namespace since 5 September 2026; basis for the schema-faithful wire examples in the simulator
OWASP GenAI Security Project · 2026
Agent Control Standard (ACS) — resource page ↗
Listed in the Agentic Security section, dated 1 September 2026
Zenity Labs (Rock Lambros) · 2026
Control Made It Into the Name: The Agent Control Standard Lands at OWASP ↗
Blog post by the project lead dated 10 September 2026 on the project’s origins and relaunch; describes ACS as a “public preview” — vendor source
Cloud Security Alliance Labs · 2026
CSA Research Note: OWASP’s 2026 LLM Top 10 and New Agent Control Standard ↗
External assessment dated 4 September 2026: ACS as an “architecture to plan around and pilot against”
OWASP GenAI Security Project — Agentic Security Initiative · 2025
OWASP Top 10 for Agentic Applications 2026 ↗
Risks ASI01–ASI10, published in December 2025; frame of reference for the risk matrix (ACS does not feature in it)
OWASP GenAI Security Project — Agentic Security Initiative · 2025
Agentic AI – Threats and Mitigations (Agentic Security Initiative resources) ↗
Threat taxonomy T1–T15 in version 1.0 from February 2025; available via the initiative’s resource overview
European Union, Official Journal · 2024
Regulation (EU) 2024/1689 (Artificial Intelligence Act / AI Act) ↗
Articles 9, 12, 14, 15, 19, 26, 50 and 72 as reference points for the regulatory mapping
European Union, Official Journal · 2026
Regulation (EU) 2026/1744 (Digital Omnibus on AI) ↗
Postpones the high-risk obligations to 2 December 2027 (Annex III) and 2 August 2028 (Annex I) respectively
National Institute of Standards and Technology · 2023
NIST AI 100-1: Artificial Intelligence Risk Management Framework (AI RMF 1.0) ↗
Voluntary framework; MANAGE 2.4 on mechanisms to supersede, disengage or deactivate AI systems
OpenTelemetry · accessed 10/2026
OpenTelemetry Semantic Conventions for Generative AI ↗
Status “Development”; baseline for comparison with the ACS trace mappings (tool spans there: execute_tool)
Open Cybersecurity Schema Framework (Linux Foundation) · accessed 10/2026
OCSF Schema 1.5.0 — Categories and Classes ↗
Cross-check of the class UIDs and names used by ACS, including 2004 Detection Finding and 6002 Application Lifecycle
OWASP Foundation / Ecma TC54 · 2025
CycloneDX Specification Overview ↗
Currently version 1.7; ACS serialises the AgBOM to CycloneDX 1.6
Microsoft (Responsible AI) · 2026
Introducing Agent Control Specification: Portable runtime governance for AI Agents ↗
For disambiguation: a separate Microsoft specification dated 2 June 2026, also abbreviated “ACS”, not part of the OWASP standard
Microsoft Open Source Blog · 2026
Introducing the Agent Governance Toolkit (Microsoft Open Source Blog) ↗
Announcement dated 2 April 2026; the toolkit serves, unchanged, as the policy engine of the ACS reference implementation
OpenAI · 2025
Continuously hardening ChatGPT Atlas against prompt injection attacks ↗
22 December 2025: prompt injection is “unlikely to ever be fully ‘solved’” — an argument for model-independent runtime controls
Want to build runtime control for your AI agents?
VamiSec supports you independently: assessment of your agent landscape, Guardian architecture and policy design based on ACS, implementation and testing — without certification promises and with a clear view of the maturity of v0.1.