# Agentic Identity on Windows: When the Process Acting on Your Behalf Isn't You

> Every AI agent on Windows in 2026 runs as the logged-on user. The cloud-identity layer has crossed the agent-attribution gap; the OS layer has not. This article maps the FIDO AATWG pillars onto Windows primitives and asks what is missing.

*Published: 2026-05-25*
*Canonical: https://paragmali.com/blog/agentic-identity-on-windows-when-the-process-acting-on-your-*
*License: CC BY 4.0 - https://creativecommons.org/licenses/by/4.0/*

---
<TLDR>
Every locally-installed AI agent on Windows in May 2026 -- Claude Desktop, ChatGPT Desktop, Cursor, GitHub Copilot CLI, the MSIX-packaged Microsoft Copilot for Windows -- runs in a process whose primary token traces to the logged-on user. `SeAccessCheck`, ETW, RPC ACLs, Defender, and on-device Conditional Access all collapse "the user asked" and "the agent decided" into one principal. The cloud-identity layer has crossed this gap: Microsoft's Entra Agent ID has been in public preview since May 19, 2025 [@ms-security-blog-agentid], and the FIDO Alliance's Agentic Authentication Technical Working Group launched its three-pillar effort on April 28, 2026 with Google's AP2 and Mastercard's Verifiable Intent as foundational donations [@fido-aatwg-pr]. The Windows OS-level analog -- a kernel-recognised `AgentPrincipal` distinct from the user SID and the package SID -- does not exist, even though the substrate primitives (AppContainer package SIDs, Kerberos S4U2Proxy, WebAuthn and Windows Hello, the TPM's Direct Anonymous Attestation, the Administrator-Protection separate-session pattern, WAM, ETW) already ship. This article maps each AATWG pillar onto the Windows primitive that already exists and the glue that does not, and argues that agent identity belongs at both layers, with the OS layer being the missing piece.
</TLDR>

## 1. Two principals walk into a syscall

A Tuesday in May 2026. Windows 11 24H2. Claude Desktop is open. In one terminal, the user types `Remove-Item -Recurse -Force .\old-builds`. In another, the agent decides to run the same command against the same path. `SeAccessCheck` returns the same answer for both. The Security event log records the same `SubjectUserSid`. [ETW](/blog/etw-how-windows-2000s-performance-hack-became-the-edr-substr/) emits the same `SubjectUserName`. Microsoft Defender attributes both deletions to the same person -- the human at the keyboard.

As far as the Windows kernel is concerned, there is exactly one principal in this story, and his name is the user [@ms-learn-sids].

Nothing is broken. No malware. No zero-day. The kernel is doing exactly what NT 3.1 shipped to do on July 27, 1993 [@wiki-nt31]: read the primary token, hand the access-check engine the user SID, the group SIDs, and the integrity-level overlay [@ms-learn-mic], and decide. The decision is correct. It is also, in 2026, an attribution failure -- because the two actors who issued those two commands are different actors, and the kernel cannot tell.

<Sidenote>The attribution-collapse claim holds for every deployment pattern of every shipping agent today, but the privilege-blast-radius framing is the strong claim for Electron-wrapped agents (full DPAPI user scope, full Kerberos ticket-granting ticket, full network egress) and a more qualified claim for MSIX-packaged agents like Microsoft Copilot for Windows, which inherit a LowBox token and a per-package DPAPI scope under AppContainer [@ms-learn-appcontainer].</Sidenote>

<Definition term="Primary token">
The kernel-resident access token attached to every Windows process at creation. It contains a user SID, a list of group SIDs, an integrity-level SID carried in a `SYSTEM_MANDATORY_LABEL_ACE` inside the token's SACL [@ms-learn-mic], and a privilege set; every `SeAccessCheck` call reads it as the authoritative statement of "who is running this process" [@ms-learn-sids].
</Definition>

The collapse is structural. Three observations make the shape visible.

First, the kernel's access-check pipeline reads the *user*. `SeAccessCheck` walks the DACL on the target object and matches each ACE against the SIDs in the primary token. The integrity-level overlay, added in Windows Vista, gates writes against the integrity label [@ms-learn-mic]; AppContainer, added in Windows 8, adds a second-principal-shaped SID to the same token group list [@ms-learn-appcontainer]; but the primary SID -- the answer the kernel returns when a downstream consumer asks "whose authority is being exercised here?" -- is the user.

Second, the cloud-identity layer has just put the dual-principal answer on the wire. On April 28, 2026, the FIDO Alliance announced the Agentic Authentication Technical Working Group [@fido-aatwg-pr]. The three pillars: Verifiable User Instructions, Agent Authentication, and Trusted Delegation for Commerce. Chairs are CVS Health, Google, and OpenAI; vice-chairs are Amazon, Google, and Okta; the parallel Payments Technical Working Group is chaired by Mastercard and Visa. Google's Agent Payments Protocol (AP2) and Mastercard's Verifiable Intent framework are the foundational donations [@ap2-blog-google; @mastercard-vi]. Independent coverage from HelpNetSecurity dated April 29, 2026 carries the same governance roster [@helpnetsecurity-aatwg]. The cloud side now has a named, governed wire-format design space for the agent-as-distinct-principal story.

Third, the OS-side gap is structural. Every layer of Windows from `SeAccessCheck` through ETW [@ms-learn-mic] through on-device Conditional Access still answers "the user" because the primary token still has only the user SID. The package SID under AppContainer is the closest signal Windows has to a second principal; the access-check rule is intersection, not addition -- "the permitted access is the intersection of that granted by the user/group SIDs and AppContainer SIDs" [@ms-learn-appcontainer]. That intersection rule is the closest thing the kernel has to a sibling-principal model, and it identifies a *package*, not an *agent*.

> **Note:** No engineering effort is required to produce this attribution failure. The kernel is functioning as designed. The design is from 1993. The user is the principal. The agent is the user. The audit log is what the audit log has always been.

What would it take, mechanically, for the kernel to know which principal was which -- and why has the answer been "the user" for the thirty-three years since NT 3.1? Both halves of that question have load-bearing histories, and those histories are older than NT itself.

## 2. From Multics to NT 3.1: the user-as-principal genealogy

1965. MIT, Bell Labs, and General Electric. Fernando Corbato of MIT and Victor Vyssotsky of Bell Telephone Laboratories present *Introduction and Overview of the Multics System* at the AFIPS Fall Joint Computer Conference. Their opening describes a general-purpose programming system intended to scale to thousands of users at a single installation [@multics-fjcc]. Multics, jointly led by MIT's Project MAC, General Electric, and Bell Laboratories [@multics-wiki], is the first operating system designed from the start around the idea that the kernel must know *whose* work each running process is doing.

The Multics inheritance is not stylistic. It is the source of the abstraction Windows NT 3.1 picks up twenty-eight years later: a *principal* is a named entity (a user, or in some systems a service account); every process belongs to exactly one principal at creation; the kernel mediates access using that principal. TENEX, BBN's PDP-10 time-sharing system from 1969 [@tenex-bitsavers], inherits the same model and ports it into the DEC product line; the Multics-to-TENEX-to-Unix lineage [@multics-hist] is the route the article reads as carrying the user-as-principal assumption forward into the design ground from which DEC VMS and later Windows NT 3.1 emerged.

<Definition term="SID (Security Identifier)">
A variable-length data structure that uniquely identifies a security principal in a Windows access decision. The canonical user-SID form is `S-1-5-21-<machine or domain>-<RID>`; every access token carries a user SID plus a list of group SIDs, and every `SeAccessCheck` call reads them as the authoritative answer to "who is running this thread?" [@ms-learn-sids].
</Definition>

The formal model came in 1971. Butler Lampson, then at Xerox Palo Alto, published *Protection* at the 5th Princeton Conference on Information Sciences and Systems, later reprinted in ACM Operating Systems Review 8(1) in January 1974 [@lampson-catalog]. Lampson's access-matrix model -- subject by object by right -- is the operational mathematics behind every modern access-control system. Read the matrix row by row and you get a capability list ("what each subject can do"); read it column by column and you get an access control list ("who can do what to this object"). Windows picks column-major: every securable object on Windows is described by a DACL, and `SeAccessCheck` is the operational realisation of Lampson's matrix on NT. The DACL is the column; the primary token is the row index; the access-check answer is the cell.

<Sidenote>The bwlampson.site author catalog is the canonical fetchable anchor for the 1971 paper [@lampson-catalog]. The Microsoft Research-hosted PDF that this corpus previously linked is dead (HTTP 404); the catalog page itself names the ACM OSR 8(1) January 1974 reprint as the journal of record.</Sidenote>

<Mermaid caption="The user-as-principal genealogy: Multics 1965 to NT 3.1 1993">
timeline
    title Genealogy of the user-as-principal model
    1965 : Multics
         : Corbato and Vyssotsky present at AFIPS FJCC
         : Per-user authentication as a kernel primitive
    1969 : TENEX
         : BBN ports the user-as-principal model to PDP-10
    1971 : Lampson's access-matrix model
         : Subject x object x right
         : Foundation for SeAccessCheck and the DACL
    1988 : Hardy's Confused Deputy
         : Authority from two sources, no way to name which
    1993 : NT 3.1 ships
         : One primary token per process, user SID as principal
</Mermaid>

Seventeen years later, in 1988, Norm Hardy writes *The Confused Deputy* at Key Logic (the company formed from the wreckage of Tymshare, where the events Hardy describes had occurred years earlier). Hardy's compiler is a FORTRAN compiler with a home-files licence; it legitimately holds authority to write into one path (the billing file `(SYSX)BILL`) so it can record per-user compilation charges, and it legitimately accepts user-supplied output paths so it can write generated `.obj` files where the user requests. A clever user supplies `(SYSX)BILL` as the output path. The compiler obediently writes the user's output over the billing record, because the compiler "had no way of expressing these intents" [@hardy-caplore].

Hardy's punchline is structural, and the article will return to it once more. "The fundamental problem is that the compiler runs with authority stemming from two sources. (That's why the compiler is a confused deputy.) ... The compiler had no way of expressing these intents!" [@hardy-caplore]. The deputy holds authority from two principals (itself, the licensed compiler; and the user it is serving), and the system the deputy talks to has no protocol for the deputy to say *which* authority it is exercising for *this* action. Any system that grants a deputy ambient authority from multiple sources without giving the deputy a way to name those sources at the syscall is a confused-deputy system by construction. The ACM Digital Library carries the canonical reprint at `10.1145/54289.871709` [@hardy-acm], with the cap-lore.com mirror as the fetchable secondary.

<Definition term="Confused Deputy">
Hardy 1988: a process holding authority delegated from one principal can be tricked into using that authority on behalf of another principal because the process has no way to attribute its actions to the right authorising principal at the syscall [@hardy-caplore]. The structural lower bound on agent attribution.
</Definition>

July 27, 1993 [@wiki-nt31]. Dave Cutler ships NT 3.1. Every process on NT carries exactly one primary token; the token's user SID is the principal; impersonation is the only way a thread can temporarily speak as a different identity, and impersonation is bounded to the thread, not the process. Microsoft Learn states the consequence verbatim: "Each time a user signs in, the system creates an access token for that user. The access token contains the user's SID, user rights, and the SIDs for any groups the user belongs to" [@ms-learn-sids]. That description is the Multics inheritance with thirty years of refinement: one principal per process, the principal is a user, the access-check is the operational form of Lampson's matrix.

This is the *user-identity* milestone, not the code-identity milestone. NT 3.1 made user identity precise. The process that ran an attached binary still had no answer to "who is this *code*?" -- and as the late-1990s ActiveX download experience would prove, that gap could not stay open.

## 3. Layering code identity on user identity: 1996 to 2017

August 7, 1996. A joint Microsoft and VeriSign press release crosses the wire: *Microsoft and VeriSign Provide First Technology For Secure Downloading of Software Over the Internet* [@ms-news-authenticode-1996]. Internet Explorer 3.0 will ship with the new model the same year. The model has a name: Authenticode. The question this section asks: did Authenticode and its successors solve the principal question, or did they only decorate it?

The pattern that emerges across five generations of [code-identity layering](/blog/windows-app-identity-33-year-reinvention/) deserves a name. Every generation answers a real failure of the one before it. Every generation adds an attribute to the access decision -- a publisher signature on the binary, a policy gate at load time, a second SID in the token, a kernel-mode code-integrity policy. And every generation leaves the runtime principal unchanged. The user is still the user. The token's primary SID is still the user SID. The downstream consumer (Defender, an ETW provider, a remote RPC server, a file-system DACL) still sees one principal.

### 3.1 Authenticode (1996, NT 4.0 with IE 3.0)

Authenticode is a load-time attribute. The publisher signs the PE on disk; the signature is a PKCS #7 blob embedded in a dedicated PE attribute certificate slot [@ms-learn-cryptography]. When the loader maps the binary, Windows can verify the signature, walk the certificate chain to a trusted root, and present the publisher name to the user (in IE 3.0's case, in the famous ActiveX install dialog). Cross-vendor code-signing history places Authenticode among the earliest widely-deployed commercial schemes to bind a publisher identity to a downloaded executable [@wikipedia-codesign; @ms-news-authenticode-1996].

<Sidenote>Authenticode is a *load-time* attribute -- the publisher signs the file on disk, not the running process. After the loader has validated the signature and mapped the image, the running process's primary token has nothing in it that records "this binary was signed by Microsoft Corporation." The runtime principal is unchanged from what the user's logon session created.</Sidenote>

The failure mode that forces the next generation is structural. A signature is descriptive ("this file is from Microsoft"), not authoritative ("this process is acting with Microsoft's authority"). A binary's publisher is attached to the file on disk; nothing about it propagates into the access decision the kernel makes when the process opens a network socket, decrypts a DPAPI blob, or impersonates over RPC.

### 3.2 SRP and AppLocker (2001, 2009)

Software Restriction Policies arrived first with Windows XP (October 2001) [@wiki-winxp] and shipped again with Windows Server 2003 (April 2003) [@wiki-srv2003]; AppLocker arrived on Windows 7 (October 22, 2009) [@wiki-win7] and Server 2008 R2 as the formal successor. Microsoft Learn says it directly: "AppLocker policies in the GPO are applied and supersede the SRP policies in the GPO and any local AppLocker policies or SRP policies" [@ms-learn-srp-applocker]. Both layers are policy gates: an administrator authors rules naming publishers, hashes, or paths, and the OS enforces the rules at process creation. The runtime token is, again, unchanged.

The failure mode is one Microsoft itself documents in unusually plain language. The AppLocker overview reads, verbatim: "AppLocker is a defense-in-depth security feature and not considered a defensible Windows security feature" [@ms-learn-applocker]. The same page directs administrators to App Control for Business when the goal is defensible threat protection. Defense-in-depth means the feature raises attacker cost; it does not promise an attacker cannot bypass it. That promise is reserved for documented security boundaries.

### 3.3 AppContainer and the package SID (Windows 8, October 26, 2012 general availability)

[AppContainer](/blog/appcontainer-and-lowbox-tokens-windowss-capability-sandbox/) is the first time the kernel carries a *second* principal-shaped SID in the token's group list. Windows 8 ships with the new sandbox; every UWP app process runs with an `S-1-15-2-...` package SID attached to its primary token, alongside the user SID and the user's group SIDs. The dual-principal model has a verbatim Microsoft Learn definition: "This dual-principal model ensures that access to sensitive resources is tightly controlled and can be managed independently for different applications ... the permitted access is the intersection of that granted by the user/group SIDs and AppContainer SIDs" [@ms-learn-appcontainer].

<Definition term="AppContainer and package SID">
The kernel sandboxing primitive shipped in Windows 8 (October 26, 2012 general availability) [@ms-learn-appcontainer; @wiki-win8]. It attaches a second SID (`S-1-15-2-...`) to a process's access token; access decisions become the intersection of user/group SIDs and the package SID, gated further by capability SIDs (`S-1-15-3-...`) the app declares in its manifest [@ms-learn-appcontainer]. The kernel-internal name for the structure is the LowBox token, which is why the relevant API is `NtCreateLowBoxToken` [@ms-learn-appcontainer-legacy].
</Definition>

The dual-principal language is real and load-bearing. It is also not what the article needs. The package SID identifies a *package* (the UWP manifest, the MSIX bundle), not an *agent role*. Nothing upstream tells Defender, ETW, or Conditional Access whether the package SID it sees represents an AI agent, a UWP calculator, or a games launcher. AppContainer also originally targeted UWP only; the legacy-applications variant arrived later as a way to retrofit unpackaged Win32 apps into the same kernel substrate [@ms-learn-appcontainer-legacy], which is the path Win32 App Isolation (June 14, 2023) extends [@ms-blogs-win32appiso].

### 3.4 App Control for Business (2017 onwards)

App Control for Business -- the policy formerly known as Windows Defender Application Control (WDAC), which arrived as a named feature in Windows 10 1709 (Fall Creators Update, released October 17, 2017) [@wiki-win10vh] -- is the kernel-mode code-integrity policy enforced by the loader itself [@ms-learn-appcontrol]. Unlike AppLocker, App Control for Business is on the documented security-boundary list when configured per the supported guidance; it can cover DLL loads, driver loads, and script-host loads with a single policy. The runtime principal is, predictably, still the user.

<Mermaid caption="Five layers of code identity added to the same primary token; the runtime principal does not change">
flowchart TD
    subgraph TokenAtRuntime["What is in the primary token"]
        US["User SID (1993)"]
        PSID["Package SID (2012)"]
        IL["Integrity level overlay (2006)"]
    end
    subgraph GateBeforeRuntime["What gates execution before the token exists"]
        AC["Authenticode signature (1996)"]
        SRP["SRP and AppLocker (2001 and 2009)"]
        WDAC["App Control for Business (2017)"]
    end
    AC --> SRP --> WDAC
    US --> PSID --> IL
    GateBeforeRuntime -.-> TokenAtRuntime
    classDef def fill:transparent
</Mermaid>

> **Note:** Each generation of Windows code identity pushed the publisher, package, or integrity attribute into the token or into a load-time gate, but the runtime principal stayed the user. The agent-attribution problem is the third instance of this pattern -- the question shifts from "who wrote this code?" to "who instructed this code right now?" but the architectural answer Windows has shipped is the same answer it shipped in 1993.

So a reader who arrived at this article believing Windows must have some way of attributing what an AI agent does, given how much identity machinery has accumulated since 1993, can now see why the belief is wrong. Authenticode signs the file on disk. AppLocker is defense-in-depth. The AppContainer package SID is per-package, not per-role. App Control for Business controls what code runs, not which principal carries the authority once code is loaded. Five generations of layering identity attributes; one user SID at the centre.

If we take the genealogy seriously and ask what a sixth generation -- a *second principal* attached to the process at the kernel layer -- would have to look like, the answer is sitting in an Insider build.

## 4. Six generations, plus the one that hasn't shipped

Read the genealogy as a forcing function and the shape becomes clear. Every generation of Windows app identity was forced by a specific failure of the one before it, and the forced response was never "replace the existing identity model" -- it was always "add an attribute or a sibling principal alongside it." That conservation rule is what makes Windows identity legible across thirty-three years. It is also what makes the seventh generation visible by its absence.

The six shipped generations are easy to enumerate.

- **Generation 1: NT 3.1 primary token (July 27, 1993).** One primary token per process. The token carries a user SID and a group SID list [@ms-learn-sids; @wiki-nt31]. The runtime principal is the user.
- **Generation 2: Authenticode (August 7, 1996).** Publisher signature attached to the binary on disk [@ms-news-authenticode-1996]. Runtime token unchanged.
- **Generation 3: SRP, then AppLocker (2001, October 22, 2009).** Group-Policy execution gates; runtime token unchanged; AppLocker explicitly defense-in-depth, not a defensible boundary [@ms-learn-applocker; @ms-learn-srp-applocker; @wiki-winxp; @wiki-win7].
- **Generation 4: AppContainer and the package SID (October 26, 2012).** Second principal-shaped SID in the token group list. Access check is the intersection of user and package authority [@ms-learn-appcontainer; @wiki-win8]. Runtime principal is still the user.
- **Generation 5: App Control for Business (2017 onwards).** Kernel-mode code-integrity policy; defensible boundary; controls what code can run, not which principal carries authority [@ms-learn-appcontrol; @wiki-win10vh].
- **Generation 6: Administrator Protection (late 2025 Insider, iterating through 2026).** The first shipping Windows feature that mints a true second logon-session principal for a bounded action, gated by a Windows Hello user-verification gesture [@ms-techcomm-adminprot].

[Administrator Protection](/blog/adminless-how-windows-finally-made-elevation-a-security-boun/) is the interesting one. The feature surfaced on Windows 11 Insider builds in late 2025; subsequent Insider build iterations have continued through 2026, with a temporary disablement and re-enablement during that window [@ms-techcomm-adminprot]. As of May 2026 it is not yet generally available; the Tech Community announcement page is the canonical reference for the design [@ms-techcomm-adminprot].

The structural innovation is worth describing precisely. Pre-Administrator-Protection elevation on Windows used split tokens: an administrator user signs in, and the Local Security Authority creates two logon sessions for the same user, one filtered and one full. When the user clicks through the User Account Control prompt, the elevating process swaps its primary token from the filtered to the full session. Both sessions belong to the same user SID; the policy boundary is integrity-level and group-driven, not principal-driven.

Administrator Protection breaks that. The feature introduces a *System-Managed Administrator Account* shadow profile.<MarginNote>The internal acronym is SMAA. It does not yet appear in `whoami /all` output on shipping builds.</MarginNote> When the user authorises an elevation through Windows Hello, the elevated process runs under the separate SMAA logon session, scoped to that elevation [@ms-techcomm-adminprot]. The Hello gesture is the verification step; the separate session is the new principal; the bound is the single elevated action.

> **Key idea:** Every generation of Windows app identity has been forced by a specific failure of the previous generation, and every forced response added an attribute or a sibling principal alongside the existing one -- but until Administrator Protection (Generation 6, Insider in 2026, not yet generally available), no shipping Windows feature minted a true second principal for a bounded action.

Administrator Protection is the existence proof. Windows *can* mint a second logon-session principal for a bounded action under a user-verification gesture. The architectural question this article asks: can the same pattern generalise from elevation to delegation?

<Mermaid caption="Six generations of Windows app identity, plus the seventh that hasn't shipped">
flowchart TD
    G1["Gen 1: NT 3.1 primary token (1993). User SID only."]
    G2["Gen 2: Authenticode (1996). Publisher attached to binary."]
    G3["Gen 3: SRP and AppLocker (2001, 2009). Execution gates."]
    G4["Gen 4: AppContainer and package SID (2012). Second SID in token."]
    G5["Gen 5: App Control for Business (2017+). Kernel-mode CI."]
    G6["Gen 6: Administrator Protection (late 2025 Insider). Second logon session for elevation."]
    G7["Gen 7 (missing): AgentPrincipal. Second logon session for delegation."]
    G1 --> G2 --> G3 --> G4 --> G5 --> G6 -.-> G7
</Mermaid>

The missing seventh generation is what this article is about. It exists at the cloud layer. Microsoft's Entra Agent ID has been in public preview since May 19, 2025 [@ms-security-blog-agentid] and was the centrepiece of the Ignite 2025 expansion that Microsoft itself called "the largest expansion of Microsoft Entra capabilities to date, extending Zero Trust principles to AI workloads" [@ms-learn-ignite25]. The FIDO Alliance has named the wire-format design space [@fido-aatwg-pr]. The IETF has an individual draft for the OAuth wire format [@ietf-draft-agentoauth]. The OS layer does not have an analog.

If Generation 6 is the existence proof at the OS layer, what just happened at the cloud layer that finally makes the delegation case unavoidable?

## 5. April 28, 2026: the wire format goes public

April 28, 2026. The FIDO Alliance press release crosses the wire. *FIDO Alliance to Develop Standards for Trusted AI Agent Interactions* [@fido-aatwg-pr]. The opening sentence is the inflection point: "The FIDO Alliance today announced initiatives to develop interoperable standards for agentic interactions and commerce." Andrew Shikiar, FIDO Alliance CEO, is the launch spokesperson. The BusinessWire mirror under wire ID `20260427506015` carries the same text [@fido-aatwg-bw], and independent press coverage from HelpNetSecurity (April 29, 2026) [@helpnetsecurity-aatwg] and PPC Land [@ppcland-aatwg] corroborate the launch.

Four interlocking pieces of news land in the same press release.

### 5.1 The three AATWG pillars

The Agentic Authentication Technical Working Group is chartered around three pillars [@fido-aatwg-pr]. The press release wording is verbatim because the wording is what every downstream protocol will quote.

- **Verifiable User Instructions.** "Enabling users to authorise AI agents through clear, phishing-resistant mechanisms so agents only perform approved actions, including transactions, without exposing credentials" [@fido-aatwg-pr]. The wire-format primitive: a passkey-signed delegation token bound to a specific intent ("approve \$50 to vendor X"), with replay protection and a short TTL.
- **Agent Authentication.** "Allowing services to verify that an AI agent is acting on behalf of an authenticated user and within defined parameters, distinguishing legitimate agents from unauthorised actors" [@fido-aatwg-pr]. The wire-format primitive: an attestation binding an agent class (optionally a specific instance) to a verifiable identity assertion.
- **Trusted Delegation for Commerce.** "Defining how agent-initiated transactions can be executed within user-controlled boundaries, with verifiable authorisation" [@fido-aatwg-pr]. The wire-format primitive: the AP2 mandate or Verifiable Intent SD-JWT chain binding an agent action to a user-approved scope and constraint set.

<PullQuote>
"The FIDO Alliance today announced initiatives to develop interoperable standards for agentic interactions and commerce ... Verifiable User Instructions ... Agent Authentication ... Trusted Delegation for Commerce." -- FIDO Alliance press release, April 28, 2026 [@fido-aatwg-pr]
</PullQuote>

### 5.2 The governance

The taxonomy matters because over-attribution is one of the easier mistakes to make in this story. AATWG chairs are CVS Health, Google, and OpenAI; vice-chairs are Amazon, Google, and Okta; the parallel Payments Technical Working Group is chaired by Mastercard and Visa [@fido-aatwg-pr]. Co-sponsors include OpenAI, Amazon, Okta, CVS Health, Visa, and Proof, plus the donating partners (Google, Mastercard). Proof Inc.'s *Know Your Agent* framework is a separate Sponsor-tier contribution to FIDO; it is not an AATWG chair or vice-chair role.

### 5.3 The foundational donations

Google's Agent Payments Protocol (AP2) and Mastercard's Verifiable Intent framework are the foundational donations [@ap2-blog-google; @mastercard-vi]. AP2 was open-sourced on September 16, 2025 [@ap2-cloud-blog] at `github.com/google-agentic-commerce/AP2` under Apache 2.0 [@ap2-github]; v0.2 shipped alongside the FIDO donation, with the v0.2 release notes calling out "Human Not Present" payments [@ap2-blog-google]. Mastercard's Verifiable Intent specification is hosted at verifiableintent.dev as Draft v0.1, describing a three-layer SD-JWT delegation chain (Identity, Intent, Action) with eight constraint types -- amount bounds, merchant allow-lists, budget caps, recurrence terms -- "cryptographically bound and machine-verifiable" [@vi-dev]. The underlying credential model is the W3C Verifiable Credentials Data Model v2.0 W3C Recommendation [@w3c-vc-2].

<Sidenote>The mandate vocabulary drifted between the September 2025 AP2 launch and the v0.2 release. The launch announcement at cloud.google.com described "Intent / Cart / Payment" mandates [@ap2-cloud-blog]; the current ap2-protocol.org spec describes "Checkout (Open / Closed) + Payment (Open / Closed)" [@ap2-protocol]. Readers diffing the September 2025 blog against the April 2026 spec should expect the vocabulary, not the underlying primitives, to have changed.</Sidenote>

### 5.4 The Microsoft parallel

Microsoft has been on the same arc for nearly a year. The Build 2025 security blog, dated May 19, 2025, introduced Microsoft Entra Agent ID in public preview: "We are excited to introduce Microsoft Entra Agent ID, which extends identity management and access capabilities to AI agents" [@ms-security-blog-agentid]. The Workday Agent System of Record and ServiceNow AI Platform integrations announced on September 16, 2025 made Entra Agent ID a directory service for agents across two of the largest enterprise SaaS platforms [@prnewswire-workday]. The Ignite 2025 expansion (November 2025) was, in Microsoft's own framing, "the largest expansion of Microsoft Entra capabilities to date, extending Zero Trust principles to AI workloads" [@ms-learn-ignite25]; the agent OAuth protocol trio shipped at the same time [@ms-learn-agentoauth], and Conditional Access for agent identities followed into preview in early 2026 [@ms-learn-caagent]. WinBuzzer (May 20, 2025) corroborates the public-preview launch [@winbuzzer-agentid].

<Mermaid caption="The three FIDO AATWG pillars and what each one carries on the wire">
flowchart LR
    P1["Pillar 1: Verifiable User Instructions"]
    P2["Pillar 2: Agent Authentication"]
    P3["Pillar 3: Trusted Delegation for Commerce"]
    W1["Wire: passkey-signed delegation token, intent-bound, short TTL"]
    W2["Wire: attestation + identity assertion, agent class or instance"]
    W3["Wire: AP2 mandate or Verifiable Intent SD-JWT chain"]
    P1 --> W1
    P2 --> W2
    P3 --> W3
</Mermaid>

So the reader's understanding shifts. Before April 28, 2026 the easy mental model was that AI agents were a product feature, not an identity question. After the FIDO press release the design space is named, governed, and partially specified on the wire. The further shift drives the rest of the article: *the cloud layer is no longer the gap*. Entra Agent ID has shipped a directory; OAuth Token Exchange has had the `act` and `may_act` claims standardised since January 2020 [@ietf-rfc-8693]; the MCP authorisation profile has its 2025-11-25 revision live [@anthropic-mcp-2025-11-25]; AP2 and Verifiable Intent are now under FIDO governance.

The gap is on the desktop. So if we take the three pillars seriously, which Windows primitive does each pillar already have a substrate for, and which Windows primitive is missing?

## 6. Mapping the three pillars onto Windows primitives

One section. Three sub-sections, one per pillar. For each: the existing Windows primitive, the API surface that exposes it, and the missing glue that turns it into a pillar-compatible building block.

### 6.1 Pillar 1: Verifiable User Instructions on Windows

The substrate exists in user mode and lives in `webauthn.dll`, the [Win32 platform-authenticator entry point](/blog/webauthn-and-passkeys-on-windows-from-ctap-to-the-credential/). Microsoft Learn describes it verbatim: "Provides Win32 apps with APIs for communicating to Windows Hello and external security keys as part of WebAuthN and CTAP specifications" [@ms-learn-webauthn-api]. Windows Hello provides the TPM-rooted user-verification gesture: "credentials are asymmetric and generated within isolated environments of TPMs" [@ms-learn-hello]. The credential provider model in Winlogon, the passkey provider plug-in model in Windows 11 24H2, and per-relying-party passkey isolation in Windows Hello for Business round out the platform-authenticator surface.

What is missing is a Windows-native *agent action approval* UI surface. Today's pieces let a relying party in the browser ask the user to authenticate to that relying party; they do not let a locally-installed agent ask the user to authorise a specific action ("approve \$50 to vendor X"; "approve `rm -rf .\old-builds`") by minting a per-action, intent-bound delegation token signed by the user's passkey with replay protection and a TTL measured in seconds. The Pillar 1 wire format AATWG is developing is exactly this kind of token; the Windows-side glue would land it as a system UI surface (analogous to UAC, but minting a passkey assertion rather than escalating an integrity level), wired into the WebAuthn platform authenticator and audited via ETW.

<Definition term="WAM (Web Account Manager)">
The Windows-resident OAuth token broker that ships with the operating system. WAM acts as an authentication broker on Windows 10 1703 and later; "WAM ensures that the refresh tokens are device bound and enables apps to acquire device bound access tokens" [@ms-learn-wam]. WAM is the on-device credential broker for Microsoft Entra ID; it does not work with third-party identity providers as of May 2026.
</Definition>

### 6.2 Pillar 2: Agent Authentication on Windows

The kernel substrate is AppContainer plus the package SID. The verbatim Microsoft Learn dual-principal model is the load-bearing citation: "the permitted access is the intersection of that granted by the user/group SIDs and AppContainer SIDs" [@ms-learn-appcontainer]. The cryptographic binding from binary to package is Authenticode signing the file [@ms-news-authenticode-1996; @wikipedia-codesign] and App Control for Business as the policy gating the loader [@ms-learn-appcontrol]. The privacy-preserving agent-class attestation primitive is [Direct Anonymous Attestation](/blog/direct-anonymous-attestation-the-zero-knowledge-proof-alread/), defined in the TPM 2.0 Library Specification by the Trusted Computing Group; the corpus's sibling DAA article describes the protocol in detail, and the verbatim TCG specification language is sourced there.

<Definition term="DAA (Direct Anonymous Attestation)">
A TPM 2.0 protocol that lets a device prove membership in a privacy-preserving group without revealing the specific device identity. In the agent setting, DAA would let an agent vendor prove "this binary is a member of the *signed Claude Desktop* class" without revealing which specific desktop installation is making the call. The protocol's group-signature mathematics is the load-bearing primitive.
</Definition>

What is missing on Windows is a kernel-recognised `AgentPrincipal` that downstream consumers treat as first-class. Today the package SID is the closest signal; it is also category-incorrect, because the package SID represents a package, not an agent role. An `AgentPrincipal` would be a third token-resident SID alongside the user SID and the package SID, with its own ACL slot in opt-in DACLs, its own `SubjectAgentSid` field in `SeAccessCheck` audit events, its own ETW header alongside `SubjectUserSid`, its own RPC binding-handle metadata, and its own claim in the access tokens WAM mints. Defender, EDR, on-device Conditional Access -- every consumer that today reads the user SID would gain a sibling field.

<Aside label="The Electron reality">
The dominant deployment pattern for AI agents on Windows desktops in May 2026 is Electron plus an NSIS or MSI per-user installer, not MSIX plus the AppContainer kernel substrate. Claude Desktop, ChatGPT Desktop, and Cursor all ship through this Electron path; GitHub Copilot CLI ships as a Node.js CLI via npm (`@github/copilot`), WinGet (`GitHub.Copilot`), or an MSI installer from the github/copilot-cli GitHub Releases page, which is a different non-MSIX-packaged path but is structurally equivalent for the purposes of this article -- no package SID, no AppContainer kernel substrate, primary token traces to the user. Each of them runs under the user's primary token without a package SID; the WebAuthn platform authenticator is available to them via `webauthn.dll`, but the kernel-substrate dual-principal model under AppContainer is not.

Win32 App Isolation, announced in public preview on June 14, 2023, is the in-flight retrofit. The launch blog describes it directly: "We are thrilled to announce the public preview launch of Win32 app isolation ... Win32 app isolation is built on the foundation of AppContainers ... AppContainer, which is recognized as a security boundary by Microsoft" [@ms-blogs-win32appiso]. Adoption among agent vendors three years later is minimal; the Pillar 2 substrate exists, but the deployment substrate that would carry it does not.
</Aside>

### 6.3 Pillar 3: Trusted Delegation for Commerce on Windows

The act-on-behalf-of primitive on Windows is [Kerberos S4U2Self and S4U2Proxy](/blog/kerberos-in-windows-the-other-half-of-ntlmless/), formally specified in Microsoft's MS-SFU Kerberos Protocol Extensions [@ms-learn-mssfu]. S4U2Self lets a service obtain a service ticket for a user without that user's password (the "for" half); S4U2Proxy lets the service then present that ticket to a back-end service on the user's behalf (the "proxy" half). Resource-Based Constrained Delegation is the modern policy form: the back-end service authors which front-end services may delegate to it. Protected Users, Authentication Policies, and Authentication Silos are the policy plumbing. WAM is the on-device token broker for Entra-side delegation [@ms-learn-wam]; Microsoft's OAuth 2.0 On-Behalf-Of flow [@ms-learn-obo-flow] is the cloud analog.

<Definition term="S4U2Self and S4U2Proxy (Service for User)">
Microsoft's Kerberos Protocol Extensions, formalised in MS-SFU, that let a server obtain a service ticket on behalf of a user without that user's password (S4U2Self) and then present that ticket to a back-end service (S4U2Proxy). They are the act-on-behalf-of primitive on Windows [@ms-learn-mssfu]. Resource-Based Constrained Delegation refines the policy: the back-end resource names the front-end services it accepts delegation from.
</Definition>

What is missing is a Macaroons-style mintable, attenuable, revocable capability-token format scoped to a per-tool allow-list. Macaroons were introduced by Birgisson, Politz, Erlingsson, Taly, Vrable, and Lentczner at NDSS 2014 (February 22, 2014) [@macaroons-ndss; @macaroons-gr]. The verbatim positioning from the Google Research abstract is the load-bearing description: "macaroons are bearer credentials, like Web cookies, macaroons embed caveats that attenuate and contextually confine when, where, by who, and for what purpose a target service should authorize requests" [@macaroons-gr]. The construction is a chained HMAC: a fresh HMAC of the previous HMAC plus a caveat. Any holder can append a caveat, derive a strictly weaker macaroon, and present it to a verifier; the verifier walks the chain, checks each caveat against its policy, and verifies the final HMAC against the issuer's secret.

<Definition term="Macaroon">
Birgisson, Politz, Erlingsson, Taly, Vrable, and Lentczner at NDSS 2014 [@macaroons-ndss]. A bearer credential constructed as a chained HMAC over caveats; any holder can derive a strictly weaker credential by appending a caveat without round-tripping the issuer, but cannot derive a stronger one. The attenuation property is what makes macaroons the natural format for per-tool agent capabilities [@macaroons-gr].
</Definition>

In a Windows-shipping Pillar 3 implementation, the agent would not present the user's TGT to a downstream tool. The agent would present a macaroon issued at agent-install time -- attenuated to the specific tools the user authorised through a Pillar 1 Verifiable User Instructions flow -- and the tool would verify the macaroon plus an ETW emission carrying both `SubjectUserSid` and `SubjectAgentSid`. Revocation would land at the issuer (the WAM-resident macaroon authority), with a Continuous Access Evaluation analog fanning out to local token caches without logging the user out.

<Mermaid caption="Pillar to Windows substrate to missing glue: the article's load-bearing architecture diagram">
flowchart LR
    subgraph P1G["Pillar 1: Verifiable User Instructions"]
        P1S["Substrate: webauthn.dll, Windows Hello, passkey provider"]
        P1M["Missing: agent-action approval UI minting intent-bound delegation tokens"]
        P1S --> P1M
    end
    subgraph P2G["Pillar 2: Agent Authentication"]
        P2S["Substrate: AppContainer package SID, Authenticode, App Control, TPM 2.0 DAA, Pluton"]
        P2M["Missing: kernel-recognised AgentPrincipal across SeAccessCheck, ETW, RPC, Defender, CA"]
        P2S --> P2M
    end
    subgraph P3G["Pillar 3: Trusted Delegation for Commerce"]
        P3S["Substrate: Kerberos S4U2Proxy, RBCD, WAM, OBO flow, ETW"]
        P3M["Missing: Macaroons-style attenuable capability tokens plus AgentPrincipalSid in ETW"]
        P3S --> P3M
    end
</Mermaid>

The proposed access-check sequence is the second load-bearing diagram. Picture an agent in its own AppContainer, with its own package SID, holding a macaroon scoped to one tool. The agent calls the tool; WAM intercepts; if the action requires fresh user verification, Hello mints a passkey assertion; `SeAccessCheck` evaluates user SID, package SID, and the proposed agent SID; ETW emits the dual-principal record.

<Mermaid caption="The proposed AgentPrincipal access-check for a single tool invocation">
sequenceDiagram
    participant Agent as Agent process
    participant WAM as WAM broker
    participant Hello as Windows Hello
    participant Kernel as SeAccessCheck
    participant ETW as ETW provider
    Agent->>WAM: request tool access with macaroon
    WAM->>WAM: verify macaroon chain
    WAM->>Hello: if intent required, mint fresh assertion
    Hello-->>WAM: passkey assertion
    WAM->>Kernel: assemble token (user SID, package SID, agent SID)
    Kernel->>Kernel: access check with three principals
    Kernel-->>Agent: granted or denied
    Kernel->>ETW: emit dual-principal record
</Mermaid>

| Pillar | Windows substrate that already ships | API surface | Missing glue |
|---|---|---|---|
| 1: Verifiable User Instructions | `webauthn.dll`, Windows Hello, passkey provider | Win32 WebAuthn API; Hello credential provider | Agent-action approval UI; intent-bound passkey delegation tokens with short TTL |
| 2: Agent Authentication | AppContainer + package SID, Authenticode + App Control, TPM 2.0 DAA, Pluton attestation | NtCreateLowBoxToken; LSASS package-SID assignment; TPM attestation | Kernel-recognised `AgentPrincipal` across `SeAccessCheck`, ETW, RPC, Defender, on-device CA |
| 3: Trusted Delegation for Commerce | Kerberos S4U2Self/S4U2Proxy, RBCD, WAM, OBO flow, ETW | MS-SFU; MSAL WAM broker; Entra OBO token endpoint | Macaroons-style per-tool capability tokens; `AgentPrincipalSid` ETW field; CAE-style fan-out for revocation |

| Deployment pattern | Token at runtime | Where DPAPI lives | Network privilege |
|---|---|---|---|
| Non-MSIX user-mode (Claude Desktop / Cursor / ChatGPT Desktop: Electron + NSIS; Copilot CLI: Node.js + npm / WinGet / MSI) | User primary token; no package SID | User DPAPI scope (decryptable by any process under the same user) | Full user network privilege; user TGT available |
| MSIX-packaged AppContainer (Microsoft Copilot for Windows) | LowBox token with package SID; integrity level usually Low | Per-package DPAPI scope (isolated from other packages) | Capability-gated network egress per app manifest |

So the substrate is largely on the box. The glue is not. What competing approaches already ship -- and which one wins?

## 7. Where the principal lives: three positions

Three architectural positions are already shipping enough code that "which one wins" is a real question. Each picks a different layer to host the agent principal: the cloud, the operating system, or the on-device token broker.

### 7.1 Cloud-only

Agent identity lives in the identity provider. Microsoft's Entra Agent ID is the reference design: agents are first-class directory objects, with their own client credentials, sign-in logs, Conditional Access policies, and audit trail in Purview [@ms-learn-agentid]. When an agent needs to call a back-end API on a user's behalf, it uses RFC 8693 Token Exchange [@ietf-rfc-8693] or Microsoft's OAuth 2.0 On-Behalf-Of flow [@ms-learn-obo-flow] to exchange the user's token for an actor-claim-carrying access token; the back-end API consumes the `act` and `may_act` claims to attribute the call.

Pros: works today, no kernel change, no Windows update required. The plumbing is fully specified at IETF [@ietf-rfc-8693; @ietf-rfc-9728; @ietf-oauth-v2-1], the Microsoft documentation is live [@ms-learn-agentoauth; @ms-learn-agentobo], and the directory exists [@ms-learn-agentid]. Cons: the OS never sees an agent principal. Every local file action, every DPAPI decrypt, every Kerberos ticket use, every RPC call inside the device collapses to the user identity. On-device endpoint detection cannot attribute. Continuous Access Evaluation knows the agent has been revoked in the cloud but cannot purge the user's local Kerberos cache or local DPAPI-protected secrets without logging the user out.

<Sidenote>Microsoft Learn makes the cloud-only constraint explicit: "Agents aren't supported for OBO (`/authorize`) flows. Supported grant types are `client_credential`, `jwt-bearer`, and `refresh_token`" [@ms-learn-agentobo]. Agent identities are confidential clients only [@ms-learn-agentoauth]; the interactive-flow path used by browser-based delegation is not available to agent entities. Cloud-only works precisely because the agent never tries to participate in a desktop user-verification gesture. AzureFeeds (January 28, 2026) records the practical consequences for Conditional Access: agent authentication is "purely machine-driven" with no MFA prompt, no device check, and no authentication-strength evaluation [@azurefeeds-caagent].</Sidenote>

### 7.2 OS-only

Hypothetical, not shipping. The kernel access-check, ETW, and RPC ACLs all carry an agent SID distinct from the user SID. Every event the kernel emits gets a `SubjectAgentSid` field next to the existing `SubjectUserSid`. The access check is a three-way intersection: user SID, package SID, agent SID. Capability SIDs gate per-resource consent the way they do today for UWP apps.

Pros: native attribution at every layer. EDR products read the agent SID directly from the kernel-supplied event header. File-system DACLs gain an explicit "deny the agent, allow the user" expression. On-device Conditional Access can refuse to release a DPAPI-protected secret if the requesting process carries an agent SID that has been revoked in Entra. Cons: requires a kernel-level change and a packaging story for non-MSIX agents (Electron in particular, the dominant deployment pattern). Without the packaging story, the kernel substrate exists but the deployment substrate does not.

### 7.3 Token broker

WAM extended with an agent-scoped token cache. The OS holds agent-scoped, attenuable tokens that any local agent process must mint from before calling a downstream API. The principal in the OS is still the user, but the *token* the agent presents to each downstream consumer is scoped to the agent.

Pros: reuses existing WAM plumbing [@ms-learn-wam]. WAM already binds refresh tokens to the device's TPM. Adding an agent-scope cache is plumbing, not architecture. Cons: cooperative. A malicious or buggy agent can bypass the broker and fall back to the user's TGT in the local Kerberos cache, the user's DPAPI master keys, or the user's network privileges. The broker can only attribute the agents that choose to be attributed.

<Aside label="Why Macaroons over OAuth bearer tokens">
A bearer OAuth access token, in OAuth 2.0 and OAuth 2.1, is a credential the bearer presents to a resource server; the server consults the issuer (via introspection or JWT signature verification) and accepts or rejects. Adding a new constraint means going back to the authorisation server and asking for a new token with the new constraint applied. Round-trip required.

A macaroon attenuates without a round-trip. The holder appends a caveat ("only for tool X", "only until 2026-05-25T15:00:00Z", "only with body hash matching `sha256:...`") and a fresh HMAC of the previous HMAC plus the caveat text. The verifier walks the chain, checks each caveat against its policy, and verifies the final HMAC against the issuer's secret. The holder cannot un-attenuate; the issuer does not have to be online. That property -- attenuation without a round-trip, by any party in the chain -- is what makes macaroons the natural format for per-tool agent capabilities [@macaroons-ndss; @macaroons-gr].
</Aside>

### 7.4 Three live spec families that complicate the picture

Three protocol families are racing in parallel and the article will not pretend any one is the obvious winner.

- **Anthropic's Model Context Protocol authorisation profile.** Revision 2025-11-25 is the current authoritative profile [@anthropic-mcp-2025-11-25], and the MCP specification index confirms 2025-11-25 as the latest pointer [@anthropic-mcp-index]. The opening sentence makes the design choice explicit: "Authorization is OPTIONAL for MCP implementations. When supported: Implementations using an HTTP-based transport SHOULD conform to this specification. Implementations using an STDIO transport SHOULD NOT follow this specification, and instead retrieve credentials from the environment" [@anthropic-mcp-2025-11-25]. The HTTP profile is OAuth 2.1 [@ietf-oauth-v2-1] plus RFC 9728 [@ietf-rfc-9728] for resource metadata, with PKCE mandatory and dynamic client registration optional.
- **Google AP2 plus Mastercard Verifiable Intent.** The W3C Verifiable Credential-shaped mandate ladder for agent-initiated commerce [@ap2-protocol; @ap2-github; @ap2-cloud-blog; @vi-dev; @w3c-vc-2]. The September 2025 launch vocabulary used Intent / Cart / Payment mandates [@ap2-cloud-blog]; the current v0.2 spec uses Checkout (Open / Closed) and Payment (Open / Closed) [@ap2-protocol]. The April 28, 2026 FIDO donation moves the spec to multi-vendor governance [@ap2-blog-google].
- **The IETF individual draft for agents on behalf of users.** `draft-oauth-ai-agents-on-behalf-of-user` by Thilina Senarath and Ayesha Dissanayaka [@ietf-draft-agentoauth]. The current revision introduces the `requested_actor` parameter in authorisation requests and the `actor_token` parameter in token requests to authenticate the agent during code-to-token exchange [@ietf-draft-agentoauth]. The original -00 revision used `requested_agent` and defined an explicit grant type `urn:ietf:params:oauth:grant-type:agent-authorization_code` [@ietf-draft-agentoauth-00]; the parameter rename is documented and recent. The draft is an individual submission, not yet a working-group document.

| Position | Principal lives in | Token format | Revocation surface |
|---|---|---|---|
| Cloud-only (Entra Agent ID + RFC 8693) | Entra directory | JWT with `act` claim | Sign-in policy + CAE |
| OS-only (hypothetical AgentPrincipal) | Kernel access token | Token-resident SID | Local SID purge + Defender |
| Token broker (WAM extended) | WAM cache (TPM-bound) | Macaroon or signed capability | WAM eviction + macaroon allow-list |
| MCP authorisation profile | MCP server's IdP | OAuth 2.1 bearer | OAuth introspection |
| AP2 plus Verifiable Intent | Mandate issuer | SD-JWT VC chain | Mandate revocation registry |
| IETF agent-OBO draft | Authorisation server | JWT with `actor_token` | OAuth introspection |

> **Key idea:** Most of the primitives exist on Windows today: AppContainer package SIDs, Kerberos S4U2Proxy, WebAuthn and Windows Hello, TPM 2.0 Direct Anonymous Attestation, the Administrator-Protection separate-session pattern, WAM, ETW. What does not exist is the coherent glue -- a kernel-recognised `AgentPrincipal` that downstream consumers treat as first-class. The article's position is that agent identity belongs at both the cloud layer and the OS layer, with the OS layer being the missing piece in May 2026. The cloud layer makes Conditional Access work; the OS layer makes endpoint detection work; both are necessary; neither is sufficient.

Even the union of all three positions has structural ceilings. What are the limits no engineering can buy?

## 8. Three ceilings no engineering can buy

Three structural ceilings constrain every agent-attribution architecture, regardless of which of the three positions wins.

### 8.1 The semantic-intent ceiling

No cryptographic primitive can distinguish "the user wanted the agent to delete this file" from "the user wanted to delete this file" once both calls go through the same syscall. The OS sees bytes, not intent. The strongest architecture binds each intent to a fresh user-verification gesture (passkey plus Hello); at the limit, this requires one gesture per syscall, which is operationally unusable. The practical optimum is *batched intent* traded off against *granularity of audit*: the user authorises a session-scoped delegation ("for the next 20 minutes, this agent may modify files under `.\old-builds`"), the system mints a macaroon attenuated to that scope, and the audit log records the macaroon issuance plus every syscall it gates. The intent is bounded by the scope of the gesture; the audit reconstructs intent after the fact from scope plus action.

### 8.2 The Confused-Deputy ceiling

Hardy 1988, in the verbatim formulation that began the genealogy. "The fundamental problem is that the compiler runs with authority stemming from two sources. (That's why the compiler is a confused deputy.) ... The compiler had no way of expressing these intents!" [@hardy-caplore]. Any system that grants a deputy ambient authority -- authority derived from multiple sources without the deputy being able to name *which* authority it intends to exercise for a given action -- is structurally susceptible to confused-deputy attacks. Capability-style attenuation (macaroons, capability SIDs in AppContainer) mitigates by forcing the deputy to name the authority on every call; it does not eliminate, because a deputy that holds two authorities can be tricked into presenting the wrong one if the protocol does not require the relying party to verify the intent.

### 8.3 The "running as the user" ceiling and the MSRC servicing-criteria rule

As long as the agent process runs under the user's primary token, the agent inherits the user's TGT, the user's DPAPI master keys, and the user's network privileges by construction. That inheritance is what makes attribution collapse. The proposed remedy in Section 6 is an `AgentPrincipal` that lives next to the user SID in the same token. The remedy depends on whether the Windows Security Response Center treats user-versus-agent as a defended security boundary.

The [MSRC servicing criteria document](/blog/windows-security-boundaries-the-document-that-decides-what-g/) defines the boundary taxonomy. The verbatim opening: "Does the vulnerability violate the goal or intent of a security boundary or a security feature? ... A security boundary provides a logical separation between the code and data of security domains with different levels of trust" [@ms-msrc-servicing]. The same document gives the kernel-mode-versus-user-mode separation as the canonical example of a security boundary, and that example is the article's anchor for what counts as a security boundary under current MSRC policy. By inference from the boundary taxonomy table, *within the same logon session and the same primary token*, a defect that requires the attacker to already be running as the user does not, by default, constitute a violation of a security boundary -- it is, under the criteria, a defense-in-depth concern rather than a CVE-eligible servicing event.

<Aside label="Why this matters for compliance">
The MSRC document is the governance object that fixes the rule. For an OS-level `AgentPrincipal` to be a defensible boundary -- and therefore for an agent-bypass to qualify as a CVE-eligible servicing event -- the document itself would have to be amended to add the user-versus-agent split to the boundary taxonomy.

That is not an engineering ask. It is a governance ask. Microsoft has amended the document before (AppContainer was added to the security-boundary list during the Windows 10 era; Win32 App Isolation is built on the foundation of AppContainers, "which is recognized as a security boundary by Microsoft" [@ms-blogs-win32appiso]). The amendment is possible. It is not obviously imminent. As of May 2026 the MSRC document does not contain agent-related boundary language.
</Aside>

That third ceiling lands the shift. The deepest part of the gap is not engineering -- it is *policy*. The engineering substrate is more or less in place; the governance posture is not. An OS-level `AgentPrincipal` either becomes a new defended boundary (a major policy shift) or ships as a feature without boundary semantics (no CVE eligibility for agent-bypass). The Confused-Deputy ceiling is the structural mirror of the same observation: the only mitigation a deputy can perform is to *name* the two authorities at the access-check, which is what `AgentPrincipal` would do.

Given the structural ceilings, what specifically is still open in May 2026?

## 9. Seven open problems

Seven numbered, unsolved problems as of May 2026. None of them are blocked by physics; all of them are blocked by some combination of plumbing, packaging convention, and policy.

> **Note:** The state-of-the-art inventory this article rests on names seven open problems; an earlier pass listed six and missed the methodological one (no shared cross-method benchmark). The seventh is restored at the end of this section, and three of the existing problems (cross-process delegation, signed-binary harvesting, and the DAA deployment chain) are walked through in worked-example form using kernel and TPM primitives the prior sections have named.

### 9.1 The Electron and Win32 packaging gap

Claude Desktop, ChatGPT Desktop, and Cursor are Electron and NSIS-installed apps; GitHub Copilot CLI is a Node.js CLI distributed via npm, WinGet, or MSI. None of them ships as MSIX. The package SID surface from AppContainer does not reach them; nothing in their primary token marks them as an agent class. Win32 App Isolation [@ms-blogs-win32appiso] is the in-flight retrofit -- adoption among agent vendors three years after the public preview is minimal. Until the dominant agent vendors ship under MSIX or Win32 App Isolation, the only kernel-level identifier the Pillar 2 substrate can grab onto does not exist for the agents readers actually have installed.

### 9.2 Cross-process delegation: a worked example

The failure mode lives at the kernel layer and is invisible from the source code of the agent. Claude Desktop on Windows 11 24H2 is a non-MSIX, NSIS-installed Electron binary whose primary process runs under the user's primary token. When that process calls `CreateProcessW(L"powershell.exe", L"-NoProfile -Command \"Remove-Item ...\"", ...)` to shell out, the kernel side of `NtCreateUserProcess` calls `PspAllocateProcess`, which calls into the security reference monitor to assign a primary token to the child. By default -- when the caller passes neither a replacement token through `CreateProcessAsUserW` nor a `PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES` entry in `STARTUPINFOEX::lpAttributeList` -- the kernel duplicates the parent's primary token verbatim. Microsoft Learn is explicit: "The new process runs in the security context of the calling process" [@ms-learn-createproc]. The child inherits the user's SID, the user's group SID list, the user's privileges, the medium integrity level, and the per-session logon SID. No `TokenAppContainerSid` is present (`GetTokenInformation(..., TokenIsAppContainer, ...)` returns zero); no `TokenPackageClaims` field is present. There is no field anywhere in the child's primary token that distinguishes "this PowerShell child was launched by Claude Desktop" from "this PowerShell child was launched by Notepad."

The rule that does work for packaged parents -- and the cliff at the unpackaged boundary -- are both in Microsoft Learn for legacy-application AppContainer behaviour: "When an unpackaged process running in an app container calls CreateProcess, the child process typically inherits the parent's token. That token includes the integrity level (IL) and app container info" [@ms-learn-appcontainer-legacy]. For an MSIX-packaged parent like Microsoft Copilot for Windows, the kernel propagates the `TokenAppContainerSid` and capability list to the child [@ms-learn-msix-container]. For an unpackaged Electron parent, the rule does not fire because there is nothing to propagate; even for the packaged parent, the package SID identifies the package, not an agent role. The semantics the article calls for -- "this child is acting on behalf of the user, and the agent making that decision is X" -- has no kernel-layer encoding today.

A hypothetical `AgentPrincipal`-preserving inheritance rule would extend the existing AppContainer rule. The pseudocode below is illustrative of an unshipped kernel routine; it cannot be executed.

```c
// PspAssignPrimaryTokenWithAgentInheritance (kernel-mode, called by
// NtCreateUserProcess via PspAllocateProcess for the SRM token path).

NTSTATUS PspAssignPrimaryTokenWithAgentInheritance(
    PEPROCESS  ChildProcess,
    PEPROCESS  ParentProcess,
    PTOKEN     ParentToken,
    PSECURITY_CAPABILITIES Caps,
    PIMAGE_SECTION_OBJECT  ChildImage)
{
    PTOKEN ChildToken;
    NTSTATUS s = SeSubProcessToken(ParentToken, &ChildToken);
    if (!NT_SUCCESS(s)) return s;

    // Existing rule (today's kernel): propagate AppContainer SID + caps
    // when the parent token is in an AppContainer.
    if (SeTokenIsAppContainer(ParentToken)) {
        SePropagateAppContainerSids(ParentToken, ChildToken);
    }

    // New rule: AgentPrincipal inheritance with refusal path.
    PTOKEN_AGENT_PRINCIPAL_INFORMATION AgentInfo =
        SeQueryAgentPrincipalInformation(ParentToken);
    if (AgentInfo != NULL) {
        // Child image must be Authenticode-signed and on the
        // AgentSID's per-tool allowlist authored at agent-install
        // time via the FIDO AATWG Pillar 1 ceremony.
        if (!SeImageIsAuthenticodeSigned(ChildImage) ||
            !SeAgentAllowlistContains(AgentInfo->AgentSid,
                                      ChildImage->SignerCertHash)) {
            ObDereferenceObject(ChildToken);
            return STATUS_AGENT_TOOL_NOT_ALLOWED;
        }
        SePropagateAgentPrincipal(AgentInfo, ChildToken);
        EtwWriteAgentChildProcessCreated(
            ParentProcess, ChildProcess, AgentInfo->AgentSid);
    }
    return PsAssignPrimaryToken(ChildProcess, ChildToken);
}
```

The refusal path is the load-bearing part. Today, `CreateProcess` from an agent process to any binary the user can execute succeeds. Under the proposed rule, the agent's per-tool allowlist is the access-check boundary: a child image not on the allowlist -- for example, an attacker-dropped `payload.exe` masquerading as PowerShell -- is refused at the syscall layer, with the refusal landing in ETW as an `AgentToolDenied` event correlated to the agent SID. Win32 App Isolation already ships an analogous inheritance-with-refusal shape for unpackaged Win32 binaries: the Application Capability Profiler produces a developer-supplied capability profile that the kernel enforces at child-process creation, with unprofiled syscalls failing the same way AppContainer fails capability-bounded calls today [@ms-learn-win32appiso-overview]. The missing piece for the agent case is the *agent* dimension on the token, not the mechanism.

> **Note:** Even if Windows ships an `AgentPrincipal`, every agent that shells out to PowerShell, Node, or Python today loses agent-attribution at the child-process boundary, because non-packaged children inherit the user's primary token unmodified. Agent vendors should assume that "shell out to a language runtime" is the default attack path; readers writing agent tools should keep operations inside the agent process where possible.

### 9.3 Revocation latency

Revoking an agent's Entra Agent ID in the cloud should fan out to a Kerberos TGT purge plus local token-cache invalidation plus a WAM cache flush, without logging the user out. The plumbing does not exist on Windows. Continuous Access Evaluation is the closest cloud-side analog -- it can short-circuit access-token reuse against a remote API on the cloud side, but it cannot reach the user's local Kerberos cache or the user's local DPAPI scope.

### 9.4 MCP authorisation alignment

Every MCP server today runs its own OAuth 2.1 plus RFC 9728 PRM dance [@anthropic-mcp-2025-11-25]. The OS-side agent principal has no role; per-tool authorisation lives above the OS and is invisible to ETW and Defender. An MCP-aware `AgentPrincipal` would let the OS surface the per-tool grant chain as part of the access-check audit record, so EDR can correlate an MCP grant to a downstream syscall.

### 9.5 DAA-for-agent-class deployment: end-to-end

TPM 2.0 Direct Anonymous Attestation can, in principle, prove "this binary is *some* Claude Desktop" without identifying the specific instance. As of May 2026 no agent vendor uses DAA as an attestation issuer for itself; the deployment glue between Pluton, Azure Attestation Service, and an AATWG Pillar 2 verifier does not exist. The cryptographic substrate is in the TPM; the deployment pipeline that would carry it is not. Working the chain end-to-end clarifies what would have to ship.

**Leg 1: the agent vendor as DAA issuer.** Anthropic, Microsoft, or Cursor plays the role of *DAA Issuer* in the canonical three-entity formulation: "The entities are the DAA Member (TPM platform or EPID-enabled microprocessor), the DAA Issuer and the DAA Verifier. The issuer is charged to verify the TPM platform during the Join step and to issue DAA credential to the platform" [@wiki-daa]. The vendor maintains a long-term issuer key pair; the public half is the basename a verifier consults. Discovery is conventionally JSON Web Key Set under OpenID Connect Discovery 1.0, the same mechanism Azure Attestation Service itself exposes for relying parties [@ms-learn-aas-concepts]. No agent vendor publishes such an endpoint today.

**Leg 2: the Join step at first run.** On first agent launch, a Windows-side broker (a proposed extension to WAM) mediates the Join with the vendor's issuer endpoint. Conceptually, the local Pluton or TPM runs `TPM2_CreatePrimary(hierarchy = TPM_RH_ENDORSEMENT, inPublic.type = TPM_ALG_ECDAA, ...)` to mint the member key, then `TPM2_Commit` to produce the ECDAA ephemeral commitments. The vendor issues an ECDAA membership credential -- not a per-device cert; the credential is unlinkable across signatures by construction -- and Pluton stores it in non-volatile memory [@ms-learn-pluton-tpm]. The user's WebAuthn-bound consent (the Pillar 1 evidence) is recorded in the vendor's audit log. The WAM broker has no agent-scoped DAA Join extension as of May 2026.

**Leg 3: the Sign step on each agent action.** Per-action, Pluton runs `TPM2_Commit` with the verifier's nonce, then `TPM2_Sign(daaMemberKey, message_digest, scheme = TPM_ALG_ECDAA)`. The WAM broker bundles the ECDAA signature into an Azure-Attestation-Service-style JWT envelope and submits it to the AATWG Pillar 2 verifier endpoint [@ms-learn-aas-overview; @ms-learn-aas-concepts]. The verifier de-serialises the JWT, runs the four-step check from Problem 6 (Authenticode chain plus Pluton EK chain plus measured-boot PCRs plus application-load PCR) plus the ECDAA verification. The verifier learns "some Anthropic Claude Desktop is making this request" but not *which* device; two consecutive actions from the same agent on the same device are cryptographically indistinguishable from two actions on different devices. The Azure Attestation Service policy engine does not carry an "agent-class membership" claim type that downstream Conditional Access can consume as a signal today.

The deployment gap, taken together, is integration rather than algorithm. Every primitive exists in the TCG TPM 2.0 specification, in the Azure Attestation Service engine, and in the WAM broker. Nobody has glued vendor-issuer plus Pluton-member plus WAM-broker plus AAS-verifier into a shipping pipeline. The corpus's sibling DAA article carries the verbatim TCG protocol detail; this section anchors the deployment chain to the Windows-side primitives Microsoft documents.

### 9.6 Signed-binary harvesting: a worked example

An attacker who steals a legitimately signed agent binary inherits any `AgentPrincipal` that would otherwise be granted to that binary -- unless attestation is bound to runtime state, which DAA alone cannot provide. The attack is the Stuxnet-class supply-chain pattern, generalised to the agent case.

The attacker compromises Anthropic's signing infrastructure -- the private-key custodian for the EV code-signing certificate, or the build pipeline that calls the custodian. The historical precedent for this exact attack shape is the 2010 Stuxnet incident, in which two distinct Authenticode driver-signing certificates were exfiltrated from JMicron Technology Corp and Realtek Semiconductor Corp (both VeriSign-issued) and used to produce kernel drivers Windows accepted as legitimate [@wiki-stuxnet]. The attacker now produces `claude-desktop-evil.exe` with the Anthropic Subject Name signed by the legitimate private key; `wintrust.dll!WinVerifyTrust` returns `S_OK`. To every existing Authenticode consumer -- App Control for Business publisher rules, AppLocker publisher conditions, Defender signer-based exclusions -- the malicious binary is indistinguishable from the legitimate Claude Desktop. If a hypothetical `AgentPrincipal` is bound to the install-time Authenticode signature alone, Windows mints the same `AgentSid` for the malicious binary; the audit trail still reads "Claude Desktop did X" because the binary cryptographically *is* Claude Desktop as far as the load-time check can tell.

The remediation runs through Pluton's measured-boot chain plus Azure Attestation Service. Microsoft Pluton "provides hardware-based root of trust, secure identity, secure attestation, and cryptographic services" [@ms-learn-pluton]; secure attestation is exactly the role this attack requires. Pluton-rooted attestation is a TPM 2.0 `TPM2_Quote` over a selected set of Platform Configuration Registers signed by an Attestation Identity Key whose endorsement chain terminates at Pluton's manufacturer-burned Endorsement Key [@ms-learn-pluton-tpm]. The PCRs that matter for distinguishing the legitimate Claude Desktop from `claude-desktop-evil.exe` are PCRs 0 through 7 (UEFI firmware, Option ROMs, boot manager, Secure Boot policy -- the pre-OS measured-boot range per the TCG PC Client Platform Firmware Profile), PCR 11 (BitLocker and the OS loader application code path, into which ELAM and kernel-mode driver measurements extend on Windows), and an application-extend PCR (PCR 12 in many shipping configurations, sometimes a virtual PCR via the TPM Base Services or VBS) carrying the SHA-256 of the on-disk agent image plus the cumulative hash of in-process module loads. The wire format the verifier evaluates is the Azure-Attestation-Service JWT envelope [@ms-learn-aas-overview; @ms-learn-aas-concepts].

The AATWG Pillar 2 verifier performs four cascaded checks in order. (1) Authenticode chain valid -- the agent binary's image hash is covered by an Authenticode signature whose chain terminates in a trusted root; this is the only check today. (2) Pluton EK chain valid -- the AAS-issued JWT was signed by an AIK whose endorsement chain terminates at a Microsoft-issued Pluton EK certificate, proving the quote came from real hardware. (3) Measured-boot PCRs in known-good set -- PCRs 0 through 11 match a reference value for the user's claimed device class and OS build (Windows 11 24H2, Secure Boot on, VBS on). (4) Application-load PCR matches the published-by-vendor measurement -- PCR 12 matches the hash the agent vendor published in a verifier-discoverable channel for the legitimate release. Step (4) is the runtime-state binding. The attacker now needs either to compromise the vendor's published-hashes channel *in addition to* the signing key, or to compromise the user's Pluton-rooted measured-boot chain *in addition to* the signing key. Both are strictly stronger compromises; both raise the attacker's cost by a hardware-vs-software factor. No agent vendor publishes the application-load-PCR reference channel today; the AATWG Pillar 2 verifier reference implementation does not exist.

### 9.7 Agent-identity benchmark gap

No published peer-reviewed benchmark suite compares the cloud, OS, and broker positions on a common agent-attribution workload as of May 2026. The closest available empirical results are vendor-internal: AP2 v0.2 demo measurements published with the September 2025 cloud.google.com launch and the subsequent ap2-protocol.org release notes [@ap2-cloud-blog; @ap2-protocol]; Microsoft Build 2025 session telemetry for WAM Token Protection latency [@ms-learn-wam]; RFC 8693 OAuth Token Exchange implementations measured in IEEE / ACM / USENIX venues since 2019 [@ietf-rfc-8693] but in non-agent configurations. None of these is a comparison; all are baselines.

The absence matters at two levels. Practitioners deploying an agent stack in 2026 cannot make principled latency, scale, or audit-completeness tradeoffs across the seven methods catalogued in Section 7 without a shared harness; a cloud-managed enterprise running Entra Agent ID plus RFC 8693 plus MCP cannot compare its per-action token-mint latency against a competing WAM-extended deployment without rerunning both stacks under the same workload. At the literature level, the field has named its primitives, sketched its composition rules, and assembled its wire formats but has not yet produced shared evaluation workloads.

A public AATWG-blessed benchmark would have to measure four axes matching the four distinct architectural moves the article catalogues: per-action token-mint latency from agent decision to capability-token presentation; ETW event volume per agent action and per agent session; attestation chain length (Pluton AIK to AAS JWT to vendor ECDAA to relying-party verify) in the Pillar 2 path; and cross-process-delegation propagation success rate (the §9.2 property -- the fraction of agent-spawned child processes that retain agent attribution end-to-end). The four axes are necessary because the seven methods make incomparable tradeoffs across them, and the only honest cross-method statement today is the negative one: no shared benchmark exists.

## 10. What to ship today

Six things a Windows engineer or agent vendor can do in May 2026 using only primitives that already ship.

1. **Ship the agent as an MSIX-packaged app to get a stable package SID.** The package SID is not an agent principal, but it is the only kernel-level identifier you can rely on today [@ms-learn-appcontainer; @ms-learn-appcontainer-legacy]. Packaging is the precondition for per-package DPAPI scope, capability-gated network egress under Windows Filtering Platform, and any future `AgentPrincipal` retrofit -- a non-packaged Electron app gets none of these.

2. **Mint agent-scoped tokens from Entra Agent ID** rather than letting the agent act under the user's delegated token [@ms-learn-agentid; @ms-learn-agentoauth]. You get Conditional Access on the agent identity, Purview agent-interaction audit fields, and a sign-in log entry distinct from the user's. Available grant types are `client_credentials`, `jwt-bearer`, and `refresh_token`; interactive flows are not supported for agent entities [@ms-learn-agentobo].

3. **Use Kerberos Resource-Based Constrained Delegation rather than unconstrained delegation.** Scope the allowed-to-delegate-to list to the specific back-end services the agent legitimately calls [@ms-learn-mssfu]. RBCD inverts the authoring point: the back-end resource names the front-end services it accepts delegation from, which is the right authoring point when the agent population changes faster than the back-end population.

4. **Route agent tool invocations through an MCP server with the 2025-11-25 OAuth 2.1 plus RFC 9728 PRM authorisation profile enabled** [@anthropic-mcp-2025-11-25; @ietf-rfc-9728; @ietf-oauth-v2-1]. Do not rely on the user's logon credentials at the tool layer. Each tool grant is then explicit, scoped, and revocable independently of the user's session.

> **Note:** The cost of MSIX packaging is paid once, at install-time, and the cost of leaving the Electron user-DPAPI scope alone is paid forever. Every future agent-attribution retrofit -- per-package DPAPI scope, capability-gated network egress, an `AgentPrincipal` token field -- depends on the package SID being there to attach to. Pay the install-time cost.

5. **Treat every locally stored agent secret as a user-DPAPI-scope liability for Electron-wrapped agents.** Any other process under the same user can decrypt it. If isolation matters, store the secret in a Virtualisation-Based Security trustlet behind Credential Guard, in an AppContainer per-package DPAPI scope, or in a Pluton-backed key. The substrate exists; the decision is whether to use it.

6. **Subscribe to the FIDO Alliance AATWG and Payments TWG mailing lists** [@fido-aatwg-pr; @fido-aatwg-landing]. Wire formats are in flight; deployment characteristics will not be settled until at least H2 2026. The mailing-list traffic is the cheapest signal you can get on what the agent-protocol wire format will look like in 2027.

<Spoiler kind="solution" label="Try this on your machine: dump your current primary token">
Open an elevated PowerShell prompt and run `whoami /all`. You will see the primary user SID, the group SIDs, the integrity-level overlay, and the enabled privileges that your shell process is currently running with -- the exact data structure the kernel reads on every `SeAccessCheck` call.

If you have an MSIX-packaged AppContainer process available (the Microsoft Store apps are the easiest source), run `Get-AppxPackage | Select Name, PackageFamilyName, SignatureKind` and then `Get-AppxPackage <Name> | Get-AppxPackageManifest` to see the capability list. The capability SIDs that show up in the manifest are the per-resource gates that AppContainer adds on top of the package SID. There is, today, no analogous `whoami /agent` command. That absence is the gap.
</Spoiler>

The first RunnableCode block gives a hands-on feel for the shape of a primary token's principal set and what the proposed `AgentPrincipal` would add. The second demonstrates macaroon attenuation so the chained-HMAC construction stops being abstract.

<RunnableCode lang="js" title="Inspecting an access-token's principal set (conceptual)">{`
// Conceptual model of a Windows access token, as whoami /all would print it.
// On a non-AppContainer process today there are user/group SIDs but no
// package SID and no proposed AgentPrincipalSid.
const tokenToday = {
  primaryUserSid: 'S-1-5-21-3623811015-3361044348-30300820-1013',
  groupSids: [
    'S-1-5-21-3623811015-3361044348-30300820-513', // Domain Users
    'S-1-5-32-545',                                // BUILTIN\\\\Users
    'S-1-5-11',                                    // Authenticated Users
  ],
  packageSid: null,        // not in an AppContainer
  agentPrincipalSid: null, // proposed in this article; not in any shipping build
  integrityLevel: 'Medium',
};

// Same agent process under the proposed seventh-generation token shape.
const tokenWithAgentPrincipal = Object.assign({}, tokenToday, {
  packageSid: 'S-1-15-2-2756086904-3023256918-1882200006-3954548928-2786400166-3567463568-3801030027',
  agentPrincipalSid: 'S-1-15-7-1001-AGENT-CLAUDE-DESKTOP',
  integrityLevel: 'Low',
});

function summarise(label, t) {
  console.log('--- ' + label + ' ---');
  console.log('Primary user SID: ' + t.primaryUserSid);
  console.log('Package SID:      ' + (t.packageSid || '(none)'));
  console.log('Agent SID:        ' + (t.agentPrincipalSid || '(none)'));
  console.log('Integrity:        ' + t.integrityLevel);
}

summarise('Token today (Electron Claude Desktop under user logon)', tokenToday);
summarise('Token after the seventh generation', tokenWithAgentPrincipal);
`}</RunnableCode>

<RunnableCode lang="js" title="Macaroon attenuation in thirty lines (conceptual)">{`
// Conceptual macaroon: each caveat is bound by a fresh HMAC over the prior
// HMAC plus the caveat text. The holder can only attenuate; never expand.
const crypto = {
  hmac(key, msg) {
    // Toy mixing function, not cryptographic. Real macaroons use HMAC-SHA256.
    let h = 2166136261;
    const data = String(key) + '|' + String(msg);
    for (let i = 0; i < data.length; i++) {
      h = Math.imul(h ^ data.charCodeAt(i), 16777619);
    }
    return ('00000000' + (h >>> 0).toString(16)).slice(-8);
  },
};

function mint(rootKey, identifier) {
  const sig = crypto.hmac(rootKey, identifier);
  return { id: identifier, caveats: [], sig };
}

function attenuate(macaroon, caveat) {
  const nextSig = crypto.hmac(macaroon.sig, caveat);
  return {
    id: macaroon.id,
    caveats: macaroon.caveats.concat([caveat]),
    sig: nextSig,
  };
}

function verify(rootKey, macaroon) {
  let sig = crypto.hmac(rootKey, macaroon.id);
  for (const c of macaroon.caveats) {
    sig = crypto.hmac(sig, c);
  }
  return sig === macaroon.sig;
}

const ROOT = 'agent-issuer-root-secret-123';
const m0 = mint(ROOT, 'agent-claude-desktop-session-42');
const m1 = attenuate(m0, 'tool = filesystem.read');
const m2 = attenuate(m1, 'path-prefix = C:\\\\Users\\\\parag\\\\projects');
const m3 = attenuate(m2, 'expires-at = 2026-05-25T15:00:00Z');

console.log('Base verified:       ' + verify(ROOT, m0));
console.log('Three-caveat chain:  ' + verify(ROOT, m3));

// Holder cannot un-attenuate. A holder who tries to drop a caveat would
// have to compute the prior signature, which requires the issuer's secret.
const tampered = { id: m3.id, caveats: m3.caveats.slice(0, 2), sig: m3.sig };
console.log('Tampered (verify):   ' + verify(ROOT, tampered));
`}</RunnableCode>

Six things you can do today; eight misconceptions you can stop carrying.

## 11. Misconceptions and practical concerns

<FAQ title="Frequently asked questions">

<FAQItem question="Doesn't Entra Agent ID solve this?">
Entra Agent ID solves the cloud-side half. It gives an agent a directory entry, a sign-in log, a Conditional Access surface, and a token-exchange path under `client_credentials`, `jwt-bearer`, and `refresh_token` grants [@ms-learn-agentid; @ms-learn-agentoauth]. What it does not do is reach inside the operating system. A locally-installed agent with an Entra Agent ID still calls the Windows file-system API under the user's primary token, decrypts user-DPAPI blobs as the user, and impersonates over RPC as the user. The OS-side attribution stays collapsed even when the cloud-side attribution is clean. Both layers are necessary; neither is sufficient.
</FAQItem>

<FAQItem question="Doesn't M365 Copilot's On-Behalf-Of flow solve this?">
The Microsoft On-Behalf-Of flow [@ms-learn-obo-flow] and RFC 8693 Token Exchange [@ietf-rfc-8693] solve the *back-end-to-back-end* delegation problem: a web API can call another web API as the user. They do not address desktop attribution. When the user's Microsoft 365 Copilot client (running on the user's desktop as the user) calls a downstream API, the cloud-side token carries the actor claims; the desktop-side process still runs under the user's primary token, and the OS-side audit trail still records the user as the syscall principal. OBO is the cloud answer to a different question.
</FAQItem>

<FAQItem question="Doesn't the package SID already give us agent attribution?">
The package SID is part of the agent attribution story, but it does not by itself constitute agent attribution. The verbatim Microsoft Learn rule is that "the permitted access is the intersection of that granted by the user/group SIDs and AppContainer SIDs" [@ms-learn-appcontainer]. That gives the access-check a way to restrict the package's authority below the user's; it does not give downstream consumers a way to distinguish "this package is an AI agent acting on a separable principal" from "this package is a UWP weather app." Treating the package SID as the agent principal also fails at the boundary every Electron-wrapped agent crosses today: those agents are not packaged, so they do not get a package SID at all.
</FAQItem>

<FAQItem question="Doesn't NT 1993 already prove Windows knows how to attribute?">
NT 3.1 solved *user* attribution. The primary token model, the user SID structure, impersonation, `SeAccessCheck` -- all of these are about distinguishing one user from another and about a thread temporarily speaking as a different identity [@ms-learn-sids]. None of them solved *code* identity (which took until 1996 with Authenticode and was still being refined in 2017 with App Control for Business) and none of them solved *agent* identity (the open problem this article is about). The article must not conflate the three. The 1993 milestone is the foundation; it is also incomplete by design for the question that arrived in 2025.
</FAQItem>

<FAQItem question="Can't we just put the agent in AppContainer and call it an agent?">
Putting the agent in AppContainer gets you a package SID, a per-package DPAPI scope, capability-gated network egress, and a LowBox token; do this regardless of whether you call it an agent. What AppContainer does not give you is a kernel-level signal that distinguishes agent semantics from app semantics. Defender, ETW, and Conditional Access read package SIDs as package identifiers, not as agent role markers. A full agent-principal answer needs both the AppContainer-style sandbox and a sibling-principal SID that downstream consumers explicitly understand to be an agent identity, separately governed and separately revocable.
</FAQItem>

<FAQItem question="Doesn't Adminless or Administrator Protection already solve this for elevation?">
Administrator Protection is the existence proof that Windows can mint a second logon-session principal for a bounded action under a Hello user-verification gesture. As of May 2026 it is in Insider preview, not generally available; the feature surfaced on Insider builds in late 2025 and subsequent Insider build iterations have continued through 2026 [@ms-techcomm-adminprot]. The architectural pattern -- separate logon session, Hello gesture, scoped to one action -- is exactly the shape the seventh-generation agent principal would take. What it does not do today is generalise to delegation. The System-Managed Administrator Account is scoped to elevation. The agent-principal version would be scoped to "this agent for the duration of this delegated session"; the policy machinery does not yet exist.
</FAQItem>

<FAQItem question="Aren't Macaroons just OAuth tokens with extra steps?">
No. Macaroons attenuate offline: the holder appends a caveat and a fresh HMAC, derives a strictly weaker macaroon, and presents it; the verifier walks the chain. OAuth bearer tokens cannot attenuate without round-tripping the authorisation server, which makes them structurally unfit for an agent that talks to many tools with many different scope shapes [@macaroons-ndss; @macaroons-gr]. See §7.3 for the worked construction.
</FAQItem>

<FAQItem question="Is this just a Windows problem?">
The Windows framing is specific because the article is specifically about Windows. The underlying problem is platform-general. iOS App Attest (`DCAppAttestService`) and the Android per-app UID model are the cross-platform analogs of an OS-level application principal; neither has a published agent-identity story as of May 2026. macOS has its own per-app code-signing and entitlement substrate; it also has no shipping agent-principal model. Linux distributions vary. The fact that Windows ships the AppContainer dual-principal substrate already, plus the Administrator Protection bounded-second-principal existence proof, plus the Pluton-rooted attestation chain, makes Windows the operating system where the seventh-generation answer is most legibly close. It is not a Windows-only problem; it is a problem where Windows is unusually well-equipped to solve it next.
</FAQItem>

</FAQ>

The position the article ends on is the one each prior section pushed toward. As of May 2026 the cloud-identity layer has crossed the agentic-identity gap. The OS layer has not. The substrate primitives are largely in place: AppContainer package SIDs and the LowBox token, Kerberos S4U2Self and S4U2Proxy, WAM with TPM-bound refresh tokens, WebAuthn and Windows Hello with TPM-rooted user verification, TPM 2.0 Direct Anonymous Attestation, the Administrator-Protection separate-logon-session pattern, ETW as an audit channel. The missing piece is a kernel-recognised `AgentPrincipal` extended from the package-SID substrate, gated by Hello-mediated Verifiable User Instructions, scoped via a macaroon-style per-tool capability layer, audited via an ETW `SubjectAgentSid` field, and revocable via a CAE-style fan-out that does not require logging the user out. The MSRC servicing criteria document is the governance object that determines whether the seventh generation is a defensible security boundary or a defense-in-depth feature; that document has not been amended.

The question is when, not whether, Windows ships the seventh generation.

<StudyGuide slug="agentic-identity-on-windows-when-the-process-acting-on-your-behalf-isnt-you" keyTerms={[
  { term: "Primary token", definition: "The kernel-resident access token attached to every Windows process at creation; carries the user SID, group SIDs, an integrity-level SID in a SYSTEM_MANDATORY_LABEL_ACE inside the token's SACL, and a privilege set." },
  { term: "SID", definition: "Security Identifier; the variable-length structure that uniquely identifies a security principal in a Windows access decision." },
  { term: "AppContainer", definition: "The kernel sandbox shipped in Windows 8 (October 26, 2012) [@wiki-win8]; attaches an S-1-15-2 package SID to the access token and gates access through the intersection of user and package authority." },
  { term: "S4U2Self / S4U2Proxy", definition: "Microsoft's Kerberos Protocol Extensions that let a server obtain a service ticket on behalf of a user without that user's password; the act-on-behalf-of primitive on Windows." },
  { term: "Confused Deputy", definition: "Hardy 1988: a process holding authority from multiple sources cannot express which authority it is exercising for a given action; the structural lower bound on agent attribution." },
  { term: "Macaroon", definition: "A bearer credential constructed as a chained HMAC over caveats; any holder can derive a strictly weaker credential by appending a caveat without round-tripping the issuer." },
  { term: "DAA", definition: "Direct Anonymous Attestation; a TPM 2.0 protocol that lets a device prove membership in a privacy-preserving group without revealing the specific device identity." },
  { term: "WAM", definition: "Web Account Manager; the on-device OAuth token broker that ships with Windows and binds refresh tokens to the TPM." },
  { term: "Administrator Protection", definition: "The Windows 11 Insider feature (late 2025 onwards, not yet GA) that mints a separate logon session under a System-Managed Administrator Account for an elevation, gated by a Windows Hello gesture." },
  { term: "AATWG", definition: "FIDO Alliance Agentic Authentication Technical Working Group; launched April 28, 2026 with three pillars: Verifiable User Instructions, Agent Authentication, Trusted Delegation for Commerce." }
]} questions={[
  { q: "What is the primary structural reason a locally-installed AI agent on Windows in 2026 cannot be attributed separately from the logged-on user?", a: "Every process on Windows carries one primary token; the token's user SID is the runtime principal; the agent process inherits the user's primary token; SeAccessCheck, ETW, RPC ACLs, Defender, and on-device Conditional Access all read the user SID as the principal." },
  { q: "Name the six shipped generations of Windows app identity and the generation that has not yet shipped.", a: "Gen 1 NT 3.1 primary token (1993); Gen 2 Authenticode (1996); Gen 3 SRP then AppLocker (2001, 2009); Gen 4 AppContainer + package SID (2012); Gen 5 App Control for Business (2017+); Gen 6 Administrator Protection (late 2025 Insider, not yet GA); Gen 7 AgentPrincipal (missing)." },
  { q: "Why does the AppContainer package SID not, by itself, constitute an agent principal?", a: "The package SID identifies a package, not an agent role; downstream consumers cannot distinguish 'this package SID is an AI agent on a separable principal' from 'this package SID is a UWP calculator'; Electron-wrapped agents do not get a package SID at all." },
  { q: "What are the three pillars of the FIDO AATWG and what wire-format primitive does each carry?", a: "Pillar 1 Verifiable User Instructions: passkey-signed delegation token bound to a specific intent with short TTL. Pillar 2 Agent Authentication: attestation plus identity assertion. Pillar 3 Trusted Delegation for Commerce: AP2 mandate or Verifiable Intent SD-JWT chain." },
  { q: "Why is attenuation without a round-trip the load-bearing property of macaroons in an agent setting?", a: "An agent talks to many tools with many scope shapes; the holder can derive a weaker per-tool macaroon by appending a caveat and a fresh HMAC without round-tripping the issuer; the holder cannot un-attenuate; the issuer does not have to be online." },
  { q: "What is the MSRC servicing-criteria policy ceiling and why does it matter for an AgentPrincipal?", a: "Under the MSRC document, within the same logon session and the same primary token, a defect that requires the attacker to already be running as the user is treated as defense-in-depth rather than a CVE-eligible servicing event; for an OS-level AgentPrincipal to be a defensible security boundary the MSRC document itself would have to be amended to add the user-versus-agent split to the boundary taxonomy." }
]} />
