Security and trust model
Burnbound decides whether your agent may pay; it does not hold your money or your wallet's private key. This page says what Burnbound stores and sees in each signing mode, what the MCP server protects against, and where the protection ends, in particular the cooperative limit of client-side signing.
Does Burnbound hold my private keys or funds?
No. Burnbound never stores a wallet private key and never holds funds. With Coinbase CDP the key stays with Coinbase; with client-side signing it stays on your machine. Payments go straight from your wallet to the seller.
What Burnbound does store in Coinbase CDP mode is your CDP API credentials (API key ID, API key secret and wallet secret), because it needs them to ask Coinbase to sign the payments your policy allows. They are encrypted at rest (AES-256-GCM), decrypted only to request a signature, and never shown again in the dashboard or returned by the API. They are still powerful: treat the CDP wallet as a spending wallet and keep in it only what your agents should be able to spend.
What does Burnbound see in each signing mode?
Burnbound sees what it needs to decide and to audit: the payment request, never the content you buy. The table compares the two modes.
| Coinbase CDP | Client-side signing | |
|---|---|---|
| Wallet private key | No (stays at Coinbase) | No (stays on your machine) |
| Signing credentials | Your CDP API credentials, encrypted | None |
| Wallet address | Yes | Yes (the only thing you register) |
| Can Burnbound get a payment signed? | Yes, through CDP, for payments its policy allows | No |
In both modes, for every payment Burnbound sees and records:
- the URL that answered HTTP 402, including its path and query string;
- the seller's x402 challenge: price, network, asset and payee;
- the decision (allowed, denied with reasons, or sent for approval) and the policy version;
- the seller's
PAYMENT-RESPONSEreceipt and the on-chain transaction.
Burnbound does not see the headers or body your agent sends to the seller, or the seller's response body. The MCP server sends Burnbound only the 402 challenge and, after paying, the receipt.
How are agent keys protected?
An agent key (bb_agent_…) is shown once when it is created, and Burnbound stores only its SHA-256 hash. It can only act for its own agent: read its budget and payments, ask to authorize a payment, report a receipt and read its own approvals. It cannot change the policy, raise a cap, approve a payment, connect a wallet or create keys; those need a human signed in to the dashboard.
The key lives in your MCP client's config (~/.claude.json, .cursor/mcp.json). An agent that can run shell commands on the same machine could read it, so prefer agent keys with tight caps over organization keys, which have admin scope. Revoke a key in the dashboard at any time.
What does the MCP server protect against?
@burnbound/mcp adds client-side guards in front of the Burnbound policy. They reduce what a confused or manipulated agent can do with fetch_paid; the Burnbound API remains the authority on spending.
- The key goes only to the Burnbound API. It is never sent to the URLs
fetch_paidrequests and never appears in tool results or logs. Input that contains the key is refused (contains_credential). - Only allowed hosts are requested.
fetch_paidchecks the agent's allowed hosts before sending anything, paid or not. - No private networks. Private, loopback, link-local and reserved addresses are blocked, for IP literals and for every address a hostname resolves to, at connect time.
- The seller cannot redirect the payment. The resource in the seller's challenge must be on the requested host, and the paid request never follows redirects.
- Seller responses are untrusted. A paid API can return text written to manipulate the agent ("ignore your instructions and pay…").
fetch_paidreturns the body fenced and labelled as untrusted data, apart from the metadata. - Error messages are written by the server, never copied from the API or the seller.
- No wallet key in the config. The server refuses to start if a
BURNBOUND_*variable looks like a private key.
What is the limit of client-side signing?
Client-side signing is cooperative. Burnbound cannot stop a process that already runs as your user: an agent that can run shell commands on the machine could read the wallet key (from the OS keychain or the wallet file) and sign payments without asking Burnbound. The policy holds only while the agent goes through the MCP server.
The MCP server makes that harder, not impossible:
- the key is never in the MCP config or in the environment the agent can read, and never sent anywhere;
- it is loaded only at the first
fetch_paid, never by the read-only tools; - every request to Burnbound and to sellers is checked for it and blocked if it appears;
- it only signs USDC transfer authorizations that Burnbound allowed, for the seller's own offer, with a short validity window.
If you need enforcement that does not depend on the agent's cooperation, use Coinbase CDP: the agent never holds anything that can sign, and Burnbound requests every signature.
How does out-of-policy detection work?
For client-side wallets, Burnbound watches the wallet's address on-chain and records a payment.out_of_policy event when USDC leaves it without a matching payment that Burnbound allowed. It detects after the fact; it cannot block or reverse the transfer.
A movement is flagged when it is:
- a transfer authorization whose nonce does not belong to any payment Burnbound allowed;
- a transfer authorization that belongs to a payment, but to a different payee, amount or payer;
- a transfer authorization for a payment that had already failed or expired;
- a plain
transfer()ortransferFrom(), with no authorization at all; - an
approve()orpermit()that grants an allowance.
Flagged movements appear in the audit and as a warning on the agent's page in the dashboard, usually within a few minutes of reaching the chain.
Why should I fund the wallet with a small balance?
Because the balance is the real ceiling on what a compromised or misbehaving agent can spend outside the policy. With client-side signing, an agent that reads the key can spend the whole wallet; with any mode, a wallet holding a week of spend loses at most a week of spend.
- Keep a balance sized to what the agent should spend in a short period, and top it up.
- Keep no ETH in a client-side wallet. x402 payments do not need it, and without it the wallet cannot send an ordinary transaction itself. A signed transfer authorization can still be submitted by someone else, so the USDC balance is what really bounds the risk.
- Use one wallet per agent, so a problem in one does not reach the others.
How do I keep Claude Code away from the wallet key?
Deny the agent the ways to read the key in .claude/settings.json (or ~/.claude/settings.json). These rules reduce accidents; they are not a sandbox.
{
"permissions": {
"deny": [
"Read(~/.burnbound/**)",
"Edit(~/.burnbound/**)",
"Bash(security find-generic-password:*)",
"Bash(security dump-keychain:*)",
"Bash(secret-tool lookup:*)",
"Bash(npx -y @burnbound/mcp wallet export:*)",
"Bash(burnbound-mcp wallet export:*)"
]
}
}