Identity Initial Overview and Big Picture#9
Conversation
Added an overview document for the Identity for Agents workstream, detailing unique identity challenges and the evolving nature of identity standards in agent systems. Signed-off-by: Eva <130791729+evabenn@users.noreply.github.com>
Added a comprehensive overview of identity, authentication, and authorization standards relevant to ACS, including existing and emerging standards, their gaps, and the role of ACS in addressing these gaps. Signed-off-by: Eva <130791729+evabenn@users.noreply.github.com>
|
|
||
| OAuth 2.0 is the foundation, but its design assumptions break for autonomous agents. The drafts under [Emerging Agent Identity Standards](#emerging-agent-identity-standards) (AIMS, AAuth, Agentic JWT, Transaction Tokens for Agents, and OAuth Identity Chaining) exist precisely because of these gaps. ACS addresses the **runtime** subset. | ||
|
|
||
| | OAuth 2.0 Assumption | How Agents Break It | What Addresses It | |
There was a problem hiding this comment.
OAuth access tokens can be arbitrarily long-lived (RFC 6749 leaves expires_in as RECOMMENDED, not REQUIRED ) and that many production deployments issue 1-hour tokens as a default.
For agents, this is architecturally unacceptable because The threat surface is continuous, not session-bounded.
| |---|---|---| | ||
| | **The client is a stable, registered software identity** with approximately constant behavior. | An agent's execution path is composed at runtime by a non-deterministic model over inputs that may include adversarial content (indirect prompt injection). A registered client with valid credentials can have its reasoning hijacked. OAuth client auth cannot distinguish "authenticated and behaving" from "authenticated and hijacked." | **ACS runtime enforcement.** No token-issuance standard can patch this; it requires inline behavioral verification at action time. | | ||
| | **Delegation is single-hop** (`user → client → resource server`). | Agent chains are `user → orchestrator → sub-agent → tool → API`. RFC 8693 Token Exchange retrofits multi-hop but leaves chain verification, mandatory scope attenuation, and revocation propagation unspecified. A **delegation chain splicing vulnerability** was disclosed on the OAuth WG list in February 2026. | OAuth Identity Chaining draft; AIMS §10.5; **ACS delegation-integrity checks** at every hop. | | ||
| | **Consent is grant-time, not action-time.** Approve scope once, client holds token until revoked. | Agents need consent that is **fresh** (user still present) and **granular** (this specific action, not just this scope). CAEP adds freshness signals; CIBA adds step-up, but **CIBA only covers client initiation**, not mid-execution re-authorization. AIMS §10.6 names this gap explicitly. | **ACS mid-execution step-up** and intent-aligned policy checks. | |
There was a problem hiding this comment.
Permission accumulation is real problem with agents too..
Assumption : Permissions are stateless between requests. Each API call is evaluated against the token's fixed scope. No concept of "accumulated effective authority."
Why Agents break it? Agents with persistent memory accumulate context, credentials, and derived permissions across sessions. A token issued for Task A remains in memory when the agent pivots to Task B. Session hijacking "inherits whatever permissions the agent has accumulated". Cross-session memory means a compromised session can poison future sessions' authority.
Solution - Session-scoped credential isolation; memory-bound token invalidation; per-action re-authorization (ACS mid-execution step-up).
|
|
||
| > **NIST signal.** The **NIST AI Agent Standards Initiative** (February 2026, NCCoE concept paper on agent identity and authorization) references this body of IETF work. ACS aligns with the same reference points. | ||
|
|
||
| ### Agent Authentication & Authorization |
There was a problem hiding this comment.
|
|
||
| They do not answer: | ||
|
|
||
| - Should this action happen, given current intent and observed agent state? |
There was a problem hiding this comment.
I think we are trying here to implement Least Agency principle.
Least Agency is the foundational AI security principle from the OWASP Top 10 for Agentic Applications. It is the agentic evolution of least privilege: dictating that agents should only have the minimum amount of autonomy and freedom to act without checking with a human necessary to perform their task.
The concept addresses the risk of AI agents acting autonomously on malicious prompts or hallucinating destructive tool-chains.Key Principles of Least Agency - 1) Autonomy must be earned: Agents should not be given "blank checks" to solve problems. For example, an agent tasked with scheduling should not possess the agency to delete or edit user accounts. 2) Constrained tool-chains: Agents should be restricted from chaining together multiple "safe" tools to execute destructive tasks or unauthorized data exfiltration (e.g., reading a CRM, then exporting it via email). 3) Action-level restrictions: Agency should be constrained at the API level (e.g., read-only access, capped transactions, or restricted destination domains
ashayraut
left a comment
There was a problem hiding this comment.
This document correctly identifies the composition boundary between token-issuance standards (AIMS, OIDC, WIMSE) and runtime enforcement (ACS). The framing is sound. However, the OAuth assumptions table has structural gaps that weaken the argument:
-> Token lifetime is treated as a refresh-token problem. It's not. The core broken assumption is that access tokens can live for 60 minutes. For agents, any token outliving the current reasoning step is ambient authority waiting to be exploited. This needs its own row.
-> Permission accumulation is invisible. OAuth assumes stateless, non-accumulating permissions per request. Agents with persistent memory carry forward effective authority across sessions — the token scope is fixed but the agent's de facto capability grows. The document doesn't name this.
-> What about position on impersonation vs. delegation? The document describes delegation chains but avoids the hard architectural question: should agents ever impersonate users, or must they always act on-behalf-of with attenuated scope? Taking a position here (or explicitly marking it as an open question) would strengthen the spec.
-> Thoughts on Revocation - its is incomplete without memory invalidation. Revoking a token stops future API calls. It doesn't undo what the agent already learned or cached from that token's access. Maybe the document should acknowledge that revocation in an agentic context requires purging derived context, not just killing the credential.
Cross-resource scope union is unaddressed. An agent holding tokens for Calendar + Email + Drive has an effective permission set no single OAuth grant authorized. The dangerous triad (sensitive data access + untrusted input exposure + external communication) emerges from this union, and per-resource aud restrictions don't prevent it.
| | 1 | **Chain Integrity**<br/>*Can the full delegation chain be named and verified end-to-end?* | A single agent task can chain through five to ten identities: user → orchestrator → sub-agent → tool → downstream API. Two failures compound: the chain is not *named* (audit collapses into "the agent did it"), and the chain is not *verifiable* (downstream resources cannot confirm the chain without trusting every intermediary). In practice the full chain is often not reconstructable end-to-end, and there is a known class of attacks where the chain itself can be spliced. | **[OAuth 2.0](https://www.rfc-editor.org/rfc/rfc6749) access tokens** identify the bearer, not the chain.<br/>**[OIDC Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html) ID tokens** name the human at the start but lose granularity at each hop.<br/>**[SPIFFE SVIDs](https://spiffe.io/docs/latest/spiffe-about/spiffe-concepts/)** identify the workload but not which call within it.<br/>**[OAuth Token Exchange (RFC 8693)](https://www.rfc-editor.org/rfc/rfc8693)** defines nested `act` claims that can express a chain, but per [§4.1](https://www.rfc-editor.org/rfc/rfc8693#section-4.1) *"prior actors identified by any nested `act` claims are informational only and are not to be considered in access control decisions."* The chain is recorded, not normatively enforceable.<br/>**[OAuth Identity Chaining draft](https://datatracker.ietf.org/doc/draft-ietf-oauth-identity-chaining/)** and **[Transaction Tokens draft](https://datatracker.ietf.org/doc/draft-ietf-oauth-transaction-tokens/)** address parts but specify neither chain verification rules nor revocation propagation as required runtime behavior.<br/>**[W3C Trace Context](https://www.w3.org/TR/trace-context/)** correlates but [does not authenticate](https://www.w3.org/TR/trace-context/#privacy-of-traceparent-field). | Every action must produce, at the moment of execution, a signed record that names the specific link in the chain and lets any participant (including the downstream resource) verify the entire chain end-to-end without trusting any intermediary. Cryptographic chain structure, mandatory scope attenuation at every hop, revocation propagation. | Pending | | ||
| | 2 | **Over-Privilege**<br/>*Was this action within the agent's purpose?* | Agents inherit broad standing privileges. Service accounts. Long-lived API keys. OAuth scopes designed for human applications. One compromised agent has the union of every permission anyone has ever granted to it. The fix is not bigger scopes; the fix is no standing privilege. | **[OAuth scopes (RFC 6749 §3.3)](https://www.rfc-editor.org/rfc/rfc6749#section-3.3)** are coarse, deployment-defined strings (e.g. `read`, `write`, `repo`). Per **[RFC 9396 §1](https://www.rfc-editor.org/rfc/rfc9396#section-1)**, scope is "sufficient... for coarse-grained authorization requests" but "not sufficient to specify fine-grained authorization requirements" — it does not express per-action, per-resource, per-data-cell intent.<br/>**RBAC and ABAC** scope by role or attribute, granted once, evaluated coarsely.<br/>**AIMS** does not require **[RAR (RFC 9396)](https://www.rfc-editor.org/rfc/rfc9396)** and treats scope semantics as deployment-specific. | Credentials minted just before the call, scoped to one downstream callee, structured (per-action, per-resource), expired in minutes. Authorization evaluated per-call against the immutable intent for the run, not per-session. | Pending | | ||
| | 3 | **Token Theft Resistance**<br/>*If a token leaks from agent memory, is it useless to the attacker?* | The agent threat model breaks OAuth's bearer-token assumption entirely. Prompt injection can exfiltrate tokens from memory. Tool outputs can leak tokens. Sub-agents can replay tokens. Logs and crash dumps capture tokens. Long-lived refresh tokens in agent memory are the worst case: a durable credential held in storage that any indirect prompt injection can read. | **[OAuth 2.0 Bearer Tokens (RFC 6750 §1.2)](https://www.rfc-editor.org/rfc/rfc6750#section-1.2)** explicitly treat possession as sufficient: *"Using a bearer token does not require a bearer to prove possession of cryptographic key material."*<br/>**API keys** are bearer secrets by definition.<br/>**[OAuth refresh tokens (RFC 6749 §1.5)](https://www.rfc-editor.org/rfc/rfc6749#section-1.5)** were designed for "the same user, returning later," which does not describe how agents work.<br/>**[DPoP (RFC 9449)](https://www.rfc-editor.org/rfc/rfc9449)** and **[OAuth 2.0 Mutual-TLS Certificate-Bound Access Tokens (RFC 8705)](https://www.rfc-editor.org/rfc/rfc8705)** solve sender-constraint but are optional extensions that most deployments do not enforce.<br/>None of these are required by the OAuth core. | All non-trivial tokens sender-constrained (DPoP or mTLS) so a leaked token is useless without the corresponding private key. Aggressive lifetime ceilings measured in minutes or seconds, not hours. No long-lived secrets in model-visible context. Credentials fetched at task start, used within a tight window, discarded at task end. | Pending | | ||
| | 4 | **Last-Mile Enforcement**<br/>*Did the resource actually enforce the decision, on every call, inside the runtime?* | The moment the action reaches a production system. All upstream identity work either holds here or fails here. Most systems today cannot distinguish an authorized action by an agent acting in good faith from the same call by an agent hijacked by indirect prompt injection. Gateway-only enforcement misses tool calls and sub-agent invocations that never cross a gateway. Cached decisions miss revocation, scope change, and freshly-discovered taint. | **API gateways and service meshes** enforce at the edge; agent tool calls never reach them.<br/>**[OAuth 2.0 resource servers (RFC 6749 §1.1)](https://www.rfc-editor.org/rfc/rfc6749#section-1.1)** validate the token but not the action's relationship to intent.<br/>**[mTLS (RFC 8705)](https://www.rfc-editor.org/rfc/rfc8705)** and **[SPIFFE](https://spiffe.io/docs/latest/spiffe-about/spiffe-concepts/)** establish workload identity but do not enforce per-action policy.<br/>None fire inside the agent runtime where the decision is made. | Enforcement fires at every tool call, inside the agent runtime, before the action executes. The runtime verifies identity, scope, taint, freshness, and intent on every call. No cached decisions; the LLM call cost dwarfs the re-authorization cost. Default-deny verified by a negative test in CI. | Pending | |
There was a problem hiding this comment.
Decision in at: https://github.com/Agent-Control-Standard/ACS/blob/main/docs/spec/instrument/specification.md#64-honoring-decisions-normative
"the Observed Agent MUST wait for the Guardian's decision up to the negotiated timeout, MUST apply it… and records every fail-open proceed as an audit event". That's exactly what last-mile enforcement means - the decision fires at every step, inside the agent runtime, before the action executes.
Worth either replacing "Pending" with a pointer to §6.4, or naming what additional layer of last-mile enforcement the workstream commits to beyond §6.4. As written, the row understates what the spec already does.
|
Also - consider changing the doc location to: |
rocklambros
left a comment
There was a problem hiding this comment.
The direction is right: trust standards establish identity but don't enforce what an authenticated agent does at runtime, and that's ACS's lane. Most citations check out too (RFC 8693/6750/9396, the OAuth-WG splicing post, NIST, Unit 42). Requesting changes on a few specific items, then this is good to go.
Before merge:
- standards.md treats WIMSE as the normative agent identifier ("WIMSE identifier required; SPIFFE conformant"), but the normative
docs/concepts/identity.mdsays ACS mandates no auth mechanism and keeps schemes like SPIFFE/OIDC off the wire, so aposix_uidoroauth_subjectdeployment stays conformant. The two pages answer "does ACS require WIMSE" in opposite ways. A mandate should land in identity.md with WG sign-off rather than here. - The AIMS "TODO Security" quote has moved on. draft-klrc-aiagent-auth-02 (2026-06-01) has Security Considerations at §13 with real prose, and §14 is now "Privacy Considerations," so the link no longer backs the quote. "AIMS scopes runtime enforcement out of its model (§13)" keeps the point.
- The "ACS §3.1 / 15 min / 5 min / 60 s" ceilings don't resolve against the spec: §3 is Wire Format, and those values aren't in docs/ or specification/. Worth marking proposed or open-work-item until there's a clause to cite.
- "the same user, returning later" isn't in RFC 6749 §1.5 (the text there is functional), so dropping the quote marks keeps it as your paraphrase. Quick check on the arXiv 2602.19555 title pairing too.
- Both files sit at repo-root identity/, outside
docs_dir, so mkdocs won't build them and they're missing from nav, while docs/concepts/identity.md already covers this space. If that's deliberate staging, note it in the file; otherwise move under docs/ and cross-link.
Smaller, not blocking: no-cache vs the fail-open §6.4 default, "detects deviation" reading as detection when intent immutability really confines scope, the mermaid fence isn't configured, "seven concepts" is eight once you count Skill. Happy to pair on the identity.md reconciliation.
Each item has a falsifying test in adapters/_common/tests/test_edge_cases.py (17 tests total). Items not requiring code changes still have tests that codify the safe behavior so a future regression would be caught. ## Items 1-12 Agent-Control-Standard#1 rfc8785 JCS consistency — test confirms fallback matches the rfc8785 package byte-for-byte on every ACS envelope shape we ship. No code change needed; a mixed-install signature mismatch would surface as test failure. Agent-Control-Standard#2 Guardian regex DoS, server-side: _matches_destructive_bash now returns "too_large" for inputs > DESTRUCTIVE_SCAN_MAX_LEN (8 KiB). The Guardian denies with reason_codes=["input_too_large"] — fail-safe direction. Previously, _common had the cap but the Guardian iterated patterns directly, leaving the server unprotected. Agent-Control-Standard#3 HA Guardian replay window: persist() now takes an exclusive flock on a .lock sidecar, re-reads on-disk state, merges (union of seen_request_ids / seen_nonces with earliest-timestamp wins), and atomically writes. check_replay re-reads the state on every call so Guardian A's writes are visible to Guardian B within one request. Cross-instance replay window closed under shared ACS_GUARDIAN_STATE_DIR. Agent-Control-Standard#4 Unbounded seen_request_ids: switched to dict {rid: timestamp}. New evict_old_request_ids() drops entries older than 2 × skew window (replay impossible past skew anyway). check_replay calls eviction opportunistically every 100 inserts. Memory bound is now O(skew_window / inter-request-time), not unbounded. Backwards- compat for list-format state files preserved. Agent-Control-Standard#5 Handshake cache TTL: do_handshake skips cache files older than ACS_HANDSHAKE_CACHE_TTL_SECONDS (default 3600s). Operator config changes propagate within the TTL. Agent-Control-Standard#6 NAT id(context) collision: WeakKeyDictionary fallback for contexts that reject attribute assignment. Last-resort path (object isn't weak-referenceable either) returns a fresh uuid4 per call and emits an audit event — pre→post correlation is lost in that path, but no silent collision. Agent-Control-Standard#7 Unicode / NULL / surrogate round-trip: emoji, NULL bytes, multi- plane unicode all sign+verify cleanly. JCS handles them via UTF-8 encoding; no code change needed. Agent-Control-Standard#8 ISO 8601 parse resilience: parse_iso8601 already accepts Z suffix, timezone offsets, millisecond + microsecond precision. Test codifies the accepted shapes + asserts garbage is rejected. Agent-Control-Standard#9 ACS_GUARDIAN_HOST_ALLOWLIST: optional env-var allowlist that restricts validate_guardian_url to specific hostnames in addition to the http/https scheme check. Defense in depth against env-var attacks that smuggle a valid http:// URL to internal services. Agent-Control-Standard#10 Cursor session-state file collision: _session_state_path now accepts an optional workspace parameter folded into the hash key. Cursor adapter passes the workspace_path / cwd so two Cursor windows with the same non-UUID conversation_id can't share state. Agent-Control-Standard#11 Guardian envelope schema validation: if jsonschema + ACS_SPEC_DIR are available, every incoming envelope is validated against request-envelope.json before policy evaluation. Malformed envelopes rejected with -32600 Invalid Request. system/ping and handshake/hello exempt because their payload shapes differ. Agent-Control-Standard#12 State-file hash length: bumped _session_state_path and _handshake_cache_path hashes from sha256[:16] (64-bit) to full sha256 (256-bit). Eliminates birthday collisions over deployment lifetime. ## Test counts after this commit (all green, 1 intentional manual skip) _common: 33 (16 security + 17 edge-cases) claude-code: 32 cursor: 50 example-guardian: 20 nat: 24 Total: 159 tests. ## Side-effects of the fixes - Round-trip test fixtures updated to use real UUID session_ids (claude-code/test_adapter.py). Old "test-cc-session" fails the new Guardian-side envelope-schema check, which is correct — non-UUID session_ids never reached the Guardian from real Claude Code. - Cursor adapter wires workspace through to load/save/record session state for Agent-Control-Standard#10 (new _workspace helper). - example_guardian.py imports DESTRUCTIVE_SCAN_MAX_LEN from acs_common to keep the cap in one place. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds the Identity for Agents workstream overview as a working document.
This PR adds
overview.md— the 5 unique runtime identity challenges that distinguish agent systems from human/workload identity (chain integrity, over-privilege, token theft resistance, last-mile enforcement, proof of intent), with each mapped to where existing standards fall short.Next steps (for working group discussion)