← Ravi and agents

Who Is Typing?

An agent and a human share one command line, and the system guessed which was which.

The problem: one command line, two kinds of user

When an AI agent and a human operator share the same command line, the system has to know who is typing. Ours guessed from a badge the agent could take off.

We were building crypto vaults into Ravi, a daemon that runs AI agents on WhatsApp and Slack. A customer sends "quero depositar 100", the agent runs ravi crypto deposit 100, and a Pix charge comes back. Approving a trade uses the same tool: the operator types ravi crypto trades approve in a terminal.

The ravi command told the two apart with a badge. Every command an agent runs carries hidden RAVI_* environment variables saying which agent and which customer. A terminal has none, so the rule was simple: no badge means the operator. That rule fails open. Removing information grants power.

The agent types shell commands, and a shell can take the badge off. A guard read each command before it ran, and three tricks got past it:

  • ravi crypto status > ~/.ravi/crypto.db. The guard saw only ravi and allowed it. The > then overwrote the ledger with the command's output.
  • env -i ./bin/r'a'vi crypto trades approve …. env -i empties the badge. The guard looked for the word ravi and did not find it in r'a'vi. The shell removes the quotes, runs ravi with no badge, and the agent approves its own trade as the operator.
  • bun script.ts. Every agent is born with an interpreter. A script can open the database directly and skip every rule.

None of these is prompt injection itself. Injection is how a customer talks the agent into trying. These are what let the attempt succeed. Security people call this the confused deputy: a program holding your authority is steered into using it for someone else.

Why it is the market's problem, not ours

Every platform that gives an agent a shell and also lets humans run the same tools has this gap. Coding agents, agent operating systems and "agents with a computer" all share one machine and one user account with the people who run them.

Three trends make it worse:

  • Agents are born powerful. Ravi's default profile gives every agent all tools plus bun, cat and xargs, because most agents are trusted helpers for their own operator. That default is right for your assistant and wrong for an agent that talks to strangers.
  • Text filters cannot keep up with a shell. Quoting, redirection, interpreters and programs that start other programs give a shell many spellings of the same action. We found three bypasses in a short session of poking.
  • Money raises the stakes. Simon Willison calls the dangerous mix the lethal trifecta: private data, untrusted input, and a way to act or send data out. A public crypto agent has all three: balances, customer messages, and the power to move funds.

Prompt injection cannot be fully prevented today. Any text the agent reads, a customer message or a token name, may carry instructions. So the question is not "can the agent be tricked?" but "what can a tricked agent reach?"

How the industry overcomes it

The consistent answer: never trust the agent's own process to enforce limits. Put the boundary where the agent cannot reach it, and make the human prove consent on their own device.

1. Sandbox the agent. Claude Code's Bash sandbox is "a boundary that the operating system enforces" around shell commands and every process they start. Command patterns are a convenience; the OS boundary is what holds. Cloud agents go further and run in a throwaway container or micro-VM per session.

2. Keep secrets outside. The agent asks for an action; a service outside the sandbox holds the key and performs it. The agent receives results, never credentials.

3. Prove identity, never assume it. The operator is recognized by something the agent cannot forge: a separate OS user, a signed token, or a login on another device. Missing proof means refuse, not "must be the boss".

4. Approve out of band. High-impact actions are confirmed by the human on a channel the agent has no access to: a passkey prompt, a biometric check, a tap in another app.

5. For payments, scope the credential to the intent. The 2025–2026 agentic payment primitives all follow one pattern: the agent gets a narrow, revocable permission, and the issuer or wallet enforces it.

PrimitiveWhat the agent holdsWhat limits it
Google AP2 (Sept 2025)Mandates signed as verifiable credentialsIntent Mandate set upfront ("price limits, timing, and other conditions"); Cart Mandate signed for the exact items and price; a non-repudiable audit trail
Stripe Shared Payment Tokens (expanded Mar 2026)A token, never the cardA Visa or Mastercard agentic network token "scoped to the customer's intent"
Visa Intelligent Commerce, Mastercard Agent PayTokenized credentials for registered agentsNetwork-side spending rules and agent verification
Coinbase Agentic Wallets (Feb 2026)A wallet whose key stays in Coinbase's enclaveSpending limits, session caps, transaction controls
Turnkey and Privy policy walletsSignatures, not keysPolicies check recipient, contract, chain and value before signing; Turnkey evaluates them inside a secure enclave

Turnkey states the principle best: "The agent never touches the private key. It receives signatures, not keys."

6. Pix in Brazil. There is no Central Bank rule yet for agents paying on their own. Today an agent prepares the payment and the person approves it with biometrics in the bank app. Finsiders (Sept 2026) argues agent authority must be "specific, limited, verifiable and revocable", built on Open Finance consent and on existing Pix Agendado and Pix Automático.

What we chose for Ravi

The agent is the front desk, never the cashier. It can ask for money to move; only a service it cannot reach moves it, and only with the customer's proof of consent.

Deposits already follow the industry pattern. The agent creates a Pix charge, and the customer pays it in their own bank app with their own biometrics. The provider's signed webhook goes straight to the money service, so a deposit lands even if the agent is down or confused.

Trades should not need the operator for every order; that does not scale. The customer confirms each trade with one tap, a reaction the service reads directly from their phone, so a tricked agent cannot fake it. Customers who want autonomy sign a mandate once, such as up to R$200 a week in approved assets, and the agent trades inside it. The operator steps in only for exceptions.

The agent only asks; the money service behind the wall moves moneywall: separate OS user or sandboxCustomer's phoneAgent (front desk)can only askPix providerMoney serviceledger, limits, mandateschecks every confirmationPolicy walletholds the keyasks in chatrequests onlypays in bank appsigned webhookone-tap confirm
money flow · the agent asks, the service decides

The agent sits outside the wall and can only send requests. Confirmations reach the service straight from the customer's phone, payments come from the Pix provider's signed webhook, and only the policy wallet can sign.

DecisionWhat it meansStatus
Agent proposes, never executesThe agent can create charges and trade proposals, nothing moreBuilt
Deposits settle without the agentSigned provider webhook to the money service; the confirmation states the exact amount paidBuilt
Sandbox and production split by constructionSeparate ledger per environment, chosen by a startup flag agents cannot changeBuilt
Customer agents get only what they needAn explicit-only profile plus a stricter shell guard (PR #624)In review
One-tap confirmation and mandates for tradesCustomer approves on their phone; mandates cap standing autonomyPlanned
Operator only for exceptionsLarge amounts, risk flags, frozen vaultsPlanned
Treasury key in a policy-engine walletSigns only allowed swaps up to set values, even if Ravi's host is compromisedPlanned
Withdrawals only to the depositor's own CPFMoney can only return to its ownerPlanned
Agents isolated from the money at OS levelSeparate OS user or sandbox that cannot read Ravi's dataPlanned

Tradeoffs we accepted

Every choice above trades some convenience or speed for a smaller worst case. These are the ones we made knowingly.

ChoiceWhat we gainWhat we give up
One-tap confirmation per tradeA tricked agent can only propose; the customer sees every orderOne tap per trade; fully hands-off trading needs a mandate
Mandates for autonomyTrading without the customer presentA tricked agent can still misuse the mandate, but only within its cap and assets
Custodial vaults (one treasury, ledger per person)Simple onboarding; no wallet for the customer to manageRavi holds other people's money: legal duties, KYC, and one key that matters a lot
Buying a policy wallet instead of building oneEnclave-enforced limits, audited by a specialistA vendor dependency and per-signature cost
Shell guards (text checks)Cheap, immediate, catches the common tricksBypassable by design; we found three gaps and three false positives in one session
OS-level isolationHolds even when every rule above has a bugReal infrastructure work; depends on how production is deployed
SQLite ledger for v0, not Postgres or TigerBeetleShips now; one file, easy to inspectSingle machine; durability needs synchronous=FULL and off-site replication

Two things we deliberately did not do yet:

  • Self-custody, where each customer holds their own key and signs each trade. It removes the honeypot but adds wallet setup for every user and changes the product.
  • Fully autonomous Pix out, where the agent sends money without a human tap. Brazilian rules for agent-initiated Pix are not settled, and withdrawals to the depositor's own CPF already cover the real need.

Where we think this is going

Agents will be treated like untrusted clients, not like employees with the operator's keys. The pieces for that already exist; what changes is that they become the default.

  • Isolation becomes table stakes. Agents that talk to the public will run in a sandbox or as their own OS user by default, the way web apps stopped running as root. Shell guards stay, but as a second layer.
  • Consent becomes a signed object. Mandates like AP2's turn "the user said yes" into a verifiable record with limits, an expiry and an audit trail. Payment rails and wallets will accept these instead of trusting the agent's word.
  • Keys move into policy engines. Money-moving agents will hold permission to request signatures, never keys. The rules live in an enclave run by a specialist, outside the agent's host.
  • Agents get verifiable identities. Card networks are already registering agents. Expect "which agent, acting for whom, under which mandate" on every payment, as standard as a card's billing address.
  • Pix gets agent rules. Brazil already has the parts: Open Finance consent, scheduled and automatic Pix, biometric approval. A Central Bank framework for agent mandates is a matter of when, not if.

For Ravi this sets the order of work: isolate customer agents, move the treasury key into a policy wallet, replace operator approval with customer taps and mandates, then add withdrawals to the depositor's own CPF. Each step shrinks what a tricked agent can reach.

Sources