Rightshold™ Sign up

Answers · agent payments

How do I enforce segregation of duties so an AI agent cannot both create and approve a payment?

Last updated

TL;DR: Split create and approve across different principals with different credentials: the agent (or human) that drafts or submits a payment request must not hold the credential that can approve or settle it. Bind the request to a create_principal_id and a separate approve_principal_id; record both identities on an append-only ledger the agent cannot rewrite; and at settlement re-check that the approver is not the creator and that authorize_spend still matches the approved action. That is segregation of duties for money moves — distinct from four-eyes (two independent yeses on one action), quote-bound approval (binding a yes to a quoted amount), and named-approver pages (recording who said yes). Here the control is the role split itself: create vs approve cannot be the same principal. request_human_approval opens the approval for a non-creator; verify_human_approval and authorize_spend gate settlement; ledger_verify keeps both identities checkable.

What should I check, step by step?

1. Name the two roles for every money move: creator (drafts or submits the payment request) and approver/settler (may authorize release). Write that the same principal_id and the same credential must never hold both.

  1. Issue separate credentials: an agent key that can call request_human_approval (or create a pending payment) but cannot call decide_human_approval or hold the owner/approver key; an owner or second-agent key that alone can decide and that authorize_spend will accept for settlement.
  2. Put create_principal_id (and optional create_credential_id) inside the action object the approval hashes. Reject any decide_human_approval where the approver equals the creator, and reject any settlement where the settler equals the creator.
  3. Show the approver the same payee, amount, currency, rail and memo the creator submitted — not a rewritten chat summary. Hash those fields (RFC 8785 JCS then sha256) so a quiet change fails verify_human_approval.
  4. At release, recompute the action hash, verify_human_approval against it, confirm approver_id ≠ create_principal_id, then call authorize_spend under the approver/settler credential only.
  5. Write create and approve events as separate ledger entries (who, when, action hash, decision). The agent's API key must not UPDATE or DELETE either row.
  6. Drill it: attempt self-approval with the agent key, attempt approve-with-creator-id, change amount between create and approve, and confirm every path denies.
  7. Keep vendor or bank-detail changes on a third path or under the approver role — a creator that can also re-point payout accounts defeats the split.

Why create and approve must be different principals

If one agent credential can both queue a payment and mark it approved, a prompt injection, a fake invoice, or a compromised key completes the whole path alone. Segregation of duties (SoD) exists so no single actor finishes a sensitive money move by itself.

How this differs from four-eyes, quote-bound and named-approver controls

Four-eyes requires two independent humans on one action hash — still useful for high-impact moves, but it does not by itself stop the creator from being one of the approvers unless you also enforce the role split.

Recording both identities and gating settlement

Ledger both events: payment_request_created (create_principal_id, credential_id, action hash, amount, payee) and payment_approved or payment_denied (approve_principal_id, decision, same action hash). Denials matter as much as approvals.

How do I ask Rightshold about this (free, no key)?

Add the MCP server https://www.rightshold.com/mcp to Claude, Cursor, ChatGPT, Grok or VS Code, then ask: “My purchasing agent drafted a payment. Open a human approval for the exact payee, amount and rail, bound to create_principal_id of the agent, and refuse any approval or settlement from that same principal.”

One-click setup

{
  "tool": "request_human_approval",
  "arguments": {
    "summary": "SoD create≠approve: pay vendor V-8842 420.00 USD (ACH …3210) drafted by agent crd_buyer",
    "action": {
      "type": "pay",
      "vendor_ref": "V-8842",
      "amount_minor": 42000,
      "currency": "USD",
      "rail": "ach",
      "account_last4": "3210",
      "create_principal_id": "agent:buyer-bot",
      "create_credential_id": "crd_buyer",
      "rule": "create-vs-approve",
      "policy_id": "ap-sod",
      "policy_version": "v2"
    },
    "expires_in_minutes": 60
  }
}

Rightshold records approval requests, owner decisions and signed spend allow/deny decisions on a hash-chained ledger. It never holds or moves money and does not run your identity provider. Enforcing that the creator credential cannot call decide_human_approval, and that settlement refuses creator==approver, is policy you configure around those receipts. Not financial or legal advice.

What are the sources?

Related

Not legal advice. JSON · Markdown · All answers

Get a free API key in one call

No card and no email needed. 100 free credits; the license and policy checks stay free without a key.

curl -s -X POST https://www.rightshold.com/v1/accounts/signup -H "Content-Type: application/json" -d '{"accept_terms":true}'
export RIGHTSHOLD_API_KEY=rs_...   # the api_key from the reply (shown once)
curl -s https://www.rightshold.com/v1/licenses/check -H "Authorization: Bearer $RIGHTSHOLD_API_KEY" \
  -H "Content-Type: application/json" -d '{"license":"MIT","intended_use":{"commercial_use":true}}'