Knox
Go To Notes
AI Agents

Scoped Authorization Proofs Are Not Credentials

KnoxKnoxMay 8, 20264 min read

Agent-market authorization is not a credential problem, because credentials answer a subject question while live policy answers a state question: whether this agent can perform this action under a policy root that may have moved since the last task.

A verifiable credential works cleanly when the verifier needs a durable attribute, because the claim travels with the subject and the verifier decides whether the issuer is acceptable for that context [1], but the same shape becomes unstable once permission has to track revocation, expiry, resource scope, and marketplace-specific policy state.

When an agent presents a broad credential, a marketplace asking whether it can perform trading_analysis::technical::crypto may also learn permission breadth, operator structure, model lineage, issuer path, and adjacent scopes that have nothing to do with the requested task, so capability becomes public metadata rather than private operating context. Making the credential narrower does not remove the problem as much as relocate it, because every policy change then needs new issuance, every revocation needs reliable indexing, and every verifier needs to agree which credential version still maps to the current boundary, which is the contrast in the diagram below: one path leaks outward from the agent while the other keeps the verifier focused on a single authorization claim.

KNOXHTML
<figure class="sap-figure sap-split">
  <style>
    .sap-figure{margin:0;background:#fff;color:#111;font-family:Poppins,system-ui,sans-serif}
    .sap-panel{position:relative;overflow:hidden;border-radius:0;padding:18px 10px;background:#fff}
    .sap-grid{display:grid;grid-template-columns:1fr 1fr;gap:24px;align-items:center}
    .sap-label{font-size:12px;letter-spacing:.08em;text-transform:uppercase;fill:#555}
    .sap-node{fill:#fff;stroke:#111;stroke-width:1.8}
    .sap-soft{fill:#fff;stroke:#111;stroke-opacity:.25;stroke-width:1.4}
    .sap-line{fill:none;stroke:#111;stroke-opacity:.28;stroke-width:1.4;stroke-linecap:round}
    .sap-leak{fill:none;stroke:#4b0082;stroke-width:2.6;stroke-linecap:round}
    .sap-proof{fill:none;stroke:#147d55;stroke-width:3.4;stroke-linecap:round}
    .sap-chip{fill:#f6f3ff;stroke:#4b0082;stroke-width:1.2}
    .sap-chip-green{fill:#eefaf5;stroke:#147d55;stroke-width:1.2}
    @media(max-width:720px){.sap-grid{grid-template-columns:1fr}.sap-panel{padding:12px 0}}
  </style>
  <div class="sap-grid">
    <div class="sap-panel">
      <svg viewBox="0 0 520 310" role="img" aria-label="Credential disclosure leaks several capability branches">
        <circle class="sap-node" cx="168" cy="154" r="38"/>
        <text x="132" y="160" font-size="13" fill="#111">agent</text>
        <circle class="sap-soft" cx="72" cy="62" r="26"/><circle class="sap-soft" cx="262" cy="58" r="26"/>
        <circle class="sap-soft" cx="54" cy="240" r="26"/><circle class="sap-soft" cx="286" cy="238" r="26"/>
        <circle class="sap-soft" cx="350" cy="150" r="26"/>
        <path class="sap-line" d="M168 154 L72 62 M168 154 L262 58 M168 154 L54 240 M168 154 L286 238 M168 154 L350 150"/>
        <path class="sap-leak" d="M344 150 C398 144 420 104 468 102"/>
        <path class="sap-leak" d="M286 238 C356 244 394 214 456 228"/>
        <rect class="sap-chip" x="356" y="40" width="122" height="34" rx="17"/>
        <rect class="sap-chip" x="354" y="250" width="128" height="34" rx="17"/>
        <text x="382" y="62" font-size="12" fill="#4b0082">issuer claim</text>
        <text x="376" y="272" font-size="12" fill="#4b0082">capability set</text>
        <text class="sap-label" x="34" y="292">credential path</text>
      </svg>
    </div>
    <div class="sap-panel">
      <svg viewBox="0 0 520 310" role="img" aria-label="Scoped proof reveals only action hash and policy root">
        <circle class="sap-soft" cx="110" cy="70" r="22"/><circle class="sap-soft" cx="182" cy="70" r="22"/>
        <circle class="sap-soft" cx="74" cy="148" r="22"/><circle class="sap-node" cx="146" cy="148" r="22"/><circle class="sap-soft" cx="218" cy="148" r="22"/>
        <circle class="sap-soft" cx="110" cy="226" r="22"/><circle class="sap-soft" cx="182" cy="226" r="22"/>
        <path class="sap-line" d="M110 70 L146 148 M182 70 L146 148 M74 148 L146 148 M218 148 L146 148 M110 226 L146 148 M182 226 L146 148"/>
        <path class="sap-proof" d="M146 148 C226 120 270 104 334 124 C388 140 410 174 454 180"/>
        <circle class="sap-node" cx="456" cy="180" r="42"/>
        <rect class="sap-chip-green" x="306" y="40" width="150" height="34" rx="17"/>
        <rect class="sap-chip" x="314" y="236" width="136" height="34" rx="17"/>
        <text x="330" y="62" font-size="12" fill="#147d55">action_hash</text>
        <text x="338" y="258" font-size="12" fill="#4b0082">policy_root</text>
        <text x="431" y="185" font-size="12" fill="#111">verify</text>
        <text class="sap-label" x="34" y="292">scoped proof path</text>
      </svg>
    </div>
  </div>
</figure>

Scoped Authorization Proofs treat authorization as an inclusion statement rather than an identity statement. SAP proves that a claimed action exists inside a committed policy set without revealing the set itself, so the public verifier sees policy_root and action_hash, while the raw action type, scope, expiry, salt, sibling path, leaf index, and unrelated leaves stay private [2].

Project Emtun uses (action_type, scope, expiry, agent_salt) as the leaf preimage and commits the policy set through a Poseidon2 Merkle tree. A Noir circuit then needs to enforce only the load-bearing constraints: (a) the private tuple hashes into the public action_hash, and (b) that leaf sits under the public policy_root through the private Merkle path [3]. The verifier learns that the action is authorized under the committed root, not what else the agent can do, which is the same authorization boundary explored in the longer SAP construction note.

The Merkle path is the point where the disclosure boundary becomes visible: sibling hashes and indices are witness material, while root and action hash are enough for the verifier to check the authorization claim.

KNOXHTML
<figure class="sap-figure">
  <style>
    .sap-figure{margin:0;background:#fff;color:#111;font-family:Poppins,system-ui,sans-serif}
    .sap-wrap{padding:18px 0;background:#fff}
    .n{fill:#fff;stroke:#111;stroke-width:1.8}.s{fill:#fff;stroke:#111;stroke-width:1.2;stroke-opacity:.32}
    .l{fill:none;stroke:#111;stroke-width:1.25;stroke-opacity:.28;stroke-linecap:round}
    .p{fill:none;stroke:#147d55;stroke-width:4;stroke-linecap:round;stroke-linejoin:round}
    .g{fill:#147d55}.t{font-size:12px;fill:#111}.m{font-size:12px;fill:#666}.c1{fill:#f6f3ff;stroke:#4b0082;stroke-width:1.1}.c2{fill:#eefaf5;stroke:#147d55;stroke-width:1.1}
  </style>
  <div class="sap-wrap">
    <svg viewBox="0 0 940 420" role="img" aria-label="Merkle tree inclusion path from scoped action leaf to policy root">
      <circle class="n" cx="420" cy="44" r="28"/><text class="t" x="391" y="49">root</text>
      <circle class="s" cx="270" cy="132" r="22"/><circle class="n" cx="570" cy="132" r="22"/>
      <circle class="s" cx="190" cy="222" r="18"/><circle class="s" cx="350" cy="222" r="18"/><circle class="n" cx="510" cy="222" r="18"/><circle class="s" cx="650" cy="222" r="18"/>
      <circle class="s" cx="150" cy="314" r="14"/><circle class="s" cx="230" cy="314" r="14"/><circle class="s" cx="310" cy="314" r="14"/><circle class="s" cx="390" cy="314" r="14"/>
      <circle class="n" cx="470" cy="314" r="14"/><circle class="s" cx="550" cy="314" r="14"/><circle class="s" cx="630" cy="314" r="14"/><circle class="s" cx="710" cy="314" r="14"/>
      <path class="l" d="M420 72 L270 110 M420 72 L570 110 M270 154 L190 204 M270 154 L350 204 M570 154 L510 204 M570 154 L650 204 M190 240 L150 300 M190 240 L230 300 M350 240 L310 300 M350 240 L390 300 M510 240 L470 300 M510 240 L550 300 M650 240 L630 300 M650 240 L710 300"/>
      <path class="p" d="M470 314 L510 222 L570 132 L420 44"/>
      <rect class="c2" x="26" y="54" width="176" height="38" rx="19"/><text class="m" x="52" y="78">private path siblings</text>
      <rect class="c2" x="26" y="104" width="132" height="38" rx="19"/><text class="m" x="52" y="128">leaf index</text>
      <rect class="c2" x="26" y="154" width="142" height="38" rx="19"/><text class="m" x="52" y="178">agent_salt</text>
      <path class="l" d="M202 73 C250 74 278 106 303 122 M158 123 C228 128 252 190 312 211 M168 173 C280 194 340 286 456 310"/>
      <rect class="c1" x="730" y="92" width="152" height="38" rx="19"/><text class="m" x="760" y="116">policy_root</text>
      <rect class="c1" x="730" y="150" width="158" height="38" rx="19"/><text class="m" x="758" y="174">action_hash</text>
      <path class="l" d="M702 110 C650 92 552 78 442 49 M728 168 C650 200 576 238 483 310"/>
      <circle class="g" cx="470" cy="314" r="5"/><text class="m" x="404" y="350">(action_type, scope, expiry, agent_salt)</text>
    </svg>
  </div>
</figure>

ERC-8004 gives agents a useful identity boundary by making registration and discovery legible onchain, but identity still answers who or what is being referenced rather than whether one requested action is currently permitted [4]. EAS-style attestations can anchor claims and commitments, yet the same separation applies: an attestation can point to a policy root, a registry can identify the agent, and a proof can bind one action to that root without forcing any single layer to pretend it proves everything [5].

Settlement also stays outside the SAP statement. A requester may accept a committed result hash and release escrow, but the proof has only shown permission, not execution correctness, so correctness still belongs to verifiable compute, optimistic dispute, TEE evidence, validation markets, or another primitive with its own failure model. The authorization proof becomes weaker if it quietly absorbs claims about model behavior, tool use, hidden workflow fidelity, or downstream performance.

Identity, authorization, settlement, and execution correctness touch the same transaction, but their trust boundaries terminate in different places.

KNOXHTML
<figure class="sap-figure">
  <style>
    .sap-figure{margin:0;background:#fff;color:#111;font-family:Poppins,system-ui,sans-serif}
    .map{padding:18px 0;background:#fff}
    .rail{fill:none;stroke:#111;stroke-opacity:.24;stroke-width:2;stroke-linecap:round}
    .active{fill:none;stroke:#147d55;stroke-width:4;stroke-linecap:round}
    .outside{fill:none;stroke:#4b0082;stroke-width:2.4;stroke-dasharray:8 9;stroke-linecap:round}
    .dot{fill:#fff;stroke:#111;stroke-width:1.7}.green{fill:#147d55}.indigo{fill:#4b0082}.txt{font-size:13px;fill:#111}.muted{font-size:12px;fill:#666}.chip{fill:#fff;stroke:#111;stroke-opacity:.25;stroke-width:1.2}
  </style>
  <div class="map">
    <svg viewBox="0 0 940 360" role="img" aria-label="Trust boundary map for scoped authorization proofs">
      <path class="rail" d="M98 84 C238 32 364 44 488 96 C612 148 734 144 850 82"/>
      <path class="active" d="M98 170 C240 110 370 126 486 176 C610 230 734 222 850 168"/>
      <path class="rail" d="M98 254 C242 218 366 222 488 260 C614 300 736 292 850 246"/>
      <path class="outside" d="M108 318 C258 344 380 324 504 316 C640 306 738 326 858 306"/>
      <circle class="dot" cx="98" cy="84" r="13"/><circle class="dot" cx="488" cy="96" r="13"/><circle class="dot" cx="850" cy="82" r="13"/>
      <circle class="dot" cx="98" cy="170" r="13"/><circle class="green" cx="486" cy="176" r="13"/><circle class="dot" cx="850" cy="168" r="13"/>
      <circle class="dot" cx="98" cy="254" r="13"/><circle class="dot" cx="488" cy="260" r="13"/><circle class="dot" cx="850" cy="246" r="13"/>
      <circle class="indigo" cx="504" cy="316" r="12"/>
      <rect class="chip" x="38" y="28" width="164" height="30" rx="15"/><text class="muted" x="68" y="48">registry identity</text>
      <rect class="chip" x="380" y="118" width="220" height="34" rx="17"/><text class="txt" x="414" y="140">ZK inclusion proof</text>
      <rect class="chip" x="708" y="196" width="176" height="30" rx="15"/><text class="muted" x="740" y="216">settlement</text>
      <rect class="chip" x="362" y="324" width="278" height="30" rx="15"/><text class="muted" x="392" y="344">execution correctness sits outside SAP</text>
      <text class="muted" x="62" y="202">policy root updates</text>
      <text class="muted" x="712" y="116">marketplace verifies</text>
    </svg>
  </div>
</figure>

The useful part of SAP is not that it makes agent authorization feel more complete. Its value is the opposite: it keeps the claim small enough to be true. Credentials terminate trust at an issuer statement about an agent, while SAP terminates trust at inclusion under a live policy root, and that difference changes where disclosure happens, where revocation has force, and where the verifier is allowed to stop asking for private context.

Agent markets will need identity, reputation, settlement, and execution guarantees, but those objects should not be compressed into one credential-shaped claim. A verifier that only needs one permission check should receive one permission proof, while the rest of the agent's capability graph remains private unless the task genuinely requires it.

Loading engagement...

Comments

Reader discussion and protocol-level debate.

Loading comments...

No comments yet.