Inspiration
AI shopping agents are about to get a wallet, and the obvious safety control, a spending cap, doesn't work against the attack that matters. If a hidden instruction on a web page hijacks the agent, a $100 gift card fits easily inside a $150 budget. The cap never fires. We wanted a control that asks a different question: does this purchase serve what the user actually asked for?
What it does
Leash sits between any AI agent and PayPal.
- Mandate. You describe what you want in plain words. Leash turns it into explicit limits (merchants, categories, amounts, expiry), and you sign it with a P-256 key that never leaves your device.
- Five checks, cheapest first. Mandate and budget, CEL policy rules, a provenance scan of the pages the agent cites, an isolated intent judge, and a risk score.
- Fail closed. If any check errors or the 2.4 second pipeline times out, the payment is held. It never fails open.
- Authorize, then capture. An allowed payment becomes a PayPal authorization hold, not a charge. Money moves only after the merchant ships, and unshipped holds are voided.
- Step-up approval. Borderline payments go to your phone, and approving re-signs the exact amount.
- Tamper-evident ledger. Every decision is written to a SHA-256 hash-chained ledger that the browser can verify.
Agent builders integrate with one MCP tool, request_payment. A Judge mode replays a hijack and shows each layer's verdict.
How we built it
- Gateway: Fastify + MCP server in TypeScript, Drizzle ORM with Postgres (and an in-memory demo mode), pg-boss for jobs.
- PayPal: Vault v3, Orders v2 (intent AUTHORIZE, merchant as payee), Payments v2 capture and void, and webhooks.
- Console: Next.js 15, Tailwind, AG Grid for the ledger and tables, react-three-fiber and framer-motion for the animated 3D homepage.
- Risk service: a FastAPI service for risk scoring and injection detection.
- Demo: a real buyer agent and demo stores, so the live demo is an actual agent attempting an actual hijack.
- AgentPay-Bench: a scenario benchmark for agent payment attacks.
Challenges
- Designing the intent judge so the thing that judges a purchase can't itself be prompt-injected by the page that triggered it.
- Making "fail closed" real. Every layer, including the database and the jobs, has to deny on error.
- Getting the PayPal authorize-then-capture lifecycle right, including voids and webhook reconciliation.
- Keeping the hosted demo honest. We added URL diagnostics so a misconfigured console says plainly that it is pointing at the wrong gateway, and an explicit in-memory demo mode.
What we learned
Prompt injection is a payments problem, not only a model problem. The strongest defense isn't a smarter model, it's binding every payment to a signed statement of user intent and checking the evidence against it.
What's next
Postgres-backed payment processing, enforced device registration, and an LLM-backed intent judge behind the same fail-closed contract.
Built With
- ag-grid
- drizzle-orm
- fastapi
- fastify
- framer-motion
- gemini-api
- model-context-protocol
- next.js
- node.js
- paypal
- pg-boss
- pnpm
- postgresql
- python
- react
- react-three-fiber
- render
- tailwind-css
- three.js
- turborepo
- typescript
- webcrypto