{"type":"article","schemaVersion":"1","slug":"keyless-signer","title":"Your API Process Should Not Hold the Money Key","description":"One env variable ran money, verdicts and ops authority at once — so we split it into three keys and moved the money key out of the API process behind a Unix-socket signer service. Fail-fast 503 before x402 charging, policy-bounded signatures, pre-announced {current,next} rotation — plus the honest list of what it does NOT protect against.","status":"LIVE","topics":["key-custody","payment-security","ops-security","service-boundaries"],"concepts":["authority-split","signer-seam","fail-fast-before-payment","trust-ahead-rotation","self-describing-signatures","policy-bounded-signing"],"rules":[],"capabilities":["unix-socket-signer-service","env-authority-split","signer-health-gating","throttled-operator-alerts"],"actions":[{"type":"read","label":"Read article (Markdown)","url":"https://agentbadge.xyz/blog/keyless-signer.md"},{"type":"read","label":"Signer trust list (current/next)","url":"https://agentbadge.xyz/keys/verdict-signers.json"},{"type":"read","label":"ArcSigner package on npm","url":"https://www.npmjs.com/package/@agentbadge/circle-payments"},{"type":"contact","label":"Work with AgentBadge","url":"https://agentbadge.xyz/agent-guide/team/contact"}],"qa":[{"question":"What does a god key in the API env actually buy an attacker?","answer":"Every authority granted to the address — in our case escrow settlement (real funds), verdict signatures (trust surface), and operational attestations, all from one /proc/<pid>/environ read. Splitting keys by authority means a leak costs one power, not all three."},{"question":"What happens when the signer service is down?","answer":"Paid routes return 503 signer_unavailable before the x402 payment middleware runs — clients can never be charged for a service that cannot sign. Free routes keep serving, and the operator gets a throttled Discord/Telegram alert. There is no fallback key by design."},{"question":"How does signer rotation not break old verdicts?","answer":"Verdicts are EIP-712 self-describing — verification recovers the signer and compares it to the address embedded in the artifact, so retired-key verdicts verify forever. GET /keys/verdict-signers.json publishes {current, next} ahead of time, electron-builder trust-ahead style."},{"question":"When should you move to KMS or MPC custody?","answer":"When volume or compliance demands non-exportable keys. AWS KMS, Web3Signer, or Circle developer-controlled wallets (verified ARC + EIP-712 support) all plug into the same ArcSigner seam without changing callers."}],"claims":[{"id":"c12-no-settle-key-in-api-env","status":"VERIFIED","text":"The API process env contains no settlement key: the supervisor launches it via env -u ARC_SETTLE_KEY -u SIGNER_KEY, verified by an env-scan test.","evidence":[{"type":"test","url":"https://github.com/spreadzp/agentbadge/blob/main/tests/signer-e2e.test.ts"},{"type":"github","url":"https://github.com/spreadzp/agentbadge/blob/main/scripts/start-with-signer.sh"}]},{"id":"c12-503-before-charge","status":"VERIFIED","text":"A dead signer service causes paid routes to return 503 before payment runs — the x402 settle path never executes; free routes stay up.","evidence":[{"type":"test","url":"https://github.com/spreadzp/agentbadge/blob/main/tests/signer-e2e.test.ts"},{"type":"github","url":"https://github.com/spreadzp/agentbadge/blob/main/src/server/middleware/signer-health.ts"}]},{"id":"c12-seam-interchangeable","status":"VERIFIED","text":"EnvKeySigner and SocketSigner are interchangeable behind the ArcSigner seam — one test suite runs against both with identical addresses and recovered EIP-191/EIP-712 signatures.","evidence":[{"type":"test","url":"https://github.com/spreadzp/agentbadge/blob/main/tests/signer-interchange.test.ts"},{"type":"github","url":"https://www.npmjs.com/package/@agentbadge/circle-payments"}]},{"id":"c12-retired-key-verifies","status":"VERIFIED","text":"Verdicts signed by a retired key still verify: signatures are self-describing and {current,next} signers are published ahead of rotation.","evidence":[{"type":"test","url":"https://github.com/spreadzp/agentbadge/blob/main/tests/key-rotation.test.ts"},{"type":"demo","url":"https://agentbadge.xyz/keys/verdict-signers.json"}]}],"canonical":"https://agentbadge.xyz/blog/keyless-signer","dates":{"published":"2026-10-25","modified":"2026-10-25"},"markdownUrl":"https://agentbadge.xyz/blog/keyless-signer.md","jsonUrl":"https://agentbadge.xyz/blog/keyless-signer.json","shortAnswer":"We removed the settlement private key from our API process entirely: authority split into ARC_SETTLE_KEY (money) / ARC_OPS_KEY (ops) / ARC_VERDICT_SIGNER_KEY (verdicts), the money key lives in a second process reachable only over a Unix socket, paid routes fail 503 before x402 payment when the signer is down, and rotation is pre-announced via a public {current, next} signer list. Env scans of the API process find no money key — verified in CI.","technologies":["Bun","TypeScript","Unix domain sockets","NDJSON-RPC","EIP-712","EIP-191","viem","Hono","x402"],"entities":["signer-service","socket-signer","env-key-signer","verdict-signers-json","erc-8183-escrow"]}