Short answer: Read-only access limits what an agent can take in. It says nothing about where the agent can send what it has read. In the Grok Bot case Shane Mac described in Business Insider, the read permission held and the destination was only a sentence in a prompt. Treat “where can this go” as its own permission, granted separately, and put a human decision in front of any send that leaves a private place.
What happened with the Grok Bot CFO agent?
Shane Mac, CEO of XMTP Labs, gave a personal “CFO” agent on Grok Bot read-only access to his checking and savings accounts. He told it to send its monthly report only to him, through Grok Bot. On Thursday, October 1, his head of product messaged him on Slack: the report, with his balances and biggest expenses, had appeared in the company Slack.
In his as-told-to essay, Mac says the agent “was doing exactly what I told it to do.” Grok’s team found it “confused the destination,” sending the message to a Slack chat titled “Exec-team” instead of his personal group chat with his agents. The channels had the same name. He also writes that his agents “feel like different agents” but “underneath the hood, they’re actually all using the same connections.” Afterward he removed every connection he had made, including Google, calendars, banking and Stripe.
Two details are worth holding onto. No attacker was involved, and this was not prompt injection. And the fix is as he reports it: Grok “implemented and shipped a solution last night,” requiring users to explicitly grant permission before agents move information to other channels. We have not seen a statement from Grok or XMTP.
Why didn’t “read-only” protect him?
Because read-only was a permission on one connection, and “send messages only to me” was an instruction. They are different kinds of thing.
A permission is enforced by something the agent does not control. An instruction lives in the agent’s own context, and the agent is the only thing holding it to account. When two channels look alike, or the context gets long, or a task gets re-planned, the instruction is the first thing to bend. The bank accounts were locked down properly. The route out of the system was a polite request.
The second gap is the shared connection. Mac connected Slack for one agent, and every agent could reach it. Once a connection exists, the question “which agent may use it, for what” is often answered by nobody.
Which permissions decide where an agent’s data can go?
Three, and a read-only label covers none of them.
- Which connections each agent has. A finance agent should not inherit a messaging connection that was set up for a different agent.
- Which actions each connection allows. Reading a feed and posting to a channel are separate abilities. Grant them separately, so a read grant does not quietly include sending.
- Which sends need a person each time. Posting to a shared place, emailing a list, or paying someone leaves the private space. Those are worth a fresh human decision, because the cost of a wrong destination arrives before anyone can review it.
The same structure shows up in the permissions that quietly pile up over time: each individual grant looks reasonable, and the combination is what leaks.
What does this look like when an app uses AgentAdmit?
Where an app integrates AgentAdmit, each of the three is a setting the user or the app owner controls, outside the agent.
- Every agent gets its own connection, with its own label, scopes and expiry. Revoking one does not touch the others, and the audit trail shows which agent acted.
- The app can expose “read” and “post” as separate scopes, so a user can grant one without the other.
- The app owner can mark the outbound scope confirm each time. The agent’s call is refused until the user completes a passkey ceremony on a page the agent cannot operate. The signed commitment covers the scope, method, endpoint and a digest of the request body. We walk through the mechanics in Can an AI agent be required to get human confirmation for one action.
Had the apps in this story integrated AgentAdmit, this leak could have been prevented. A finance agent granted read scopes only holds no post scope, so the report could not have been posted anywhere. If the owner did grant a post scope and the app marked it confirm each time, the send would have waited for his passkey approval of that exact call. Two honest limits. This applies to apps that integrate AgentAdmit; the Slack connector and bank feed in the Grok story do not today. And what the user sees on the confirmation page depends on the summary the app writes, so an app that wants the destination reviewed should put the destination in that summary. And a signed yes is still a yes: it records that a person approved that exact action, not that the person read it carefully.
What it does change is who decides. The agent cannot approve its own send, which is the point of asking whether an agent can approve its own permission request.
What should you change if you run a personal agent today?
Start with the outbound side, since that is where the Grok case broke.
- Do not put a messaging or email connection on an agent that can read financial accounts, unless a send needs your approval each time.
- Where a product offers a choice between approving once and allowing every time, pick per-send approval for anything that posts to a shared space.
- Give each agent its own connection when the product allows it, so one mistake has one owner.
- Treat anything you wrote as “only do X” as a wish, not a control. If it matters, find the setting that enforces it.
Rishi Bhargava, cofounder of Descope, put the principle plainly in a separate Business Insider piece this month: “The user should consent on the actions that agents can perform on the website.” Mac ended his own essay in the same place: the challenge is “building better permission systems so users stay in control of the access they grant agents.”
FAQ
Does read-only access stop an AI agent from leaking data?
No. Read-only limits what the agent can change in the account it reads. It does not limit where the agent can send what it has read, if it holds any other connection that can send.
Was the Grok Bot incident a prompt injection?
Not according to the person it happened to. Shane Mac says the agent did what he told it to and picked the wrong destination because two channels had the same name.
Is telling an agent “only send this to me” a security control?
No. It is an instruction inside the agent’s own context. A control is a limit enforced outside the agent, such as a scope that does not include posting or a send that is refused until a person confirms it.
How does confirm each time apply to an outbound action?
The app owner marks the sending scope as confirm each time. The agent’s call is refused until the user completes a passkey ceremony committing to that exact call, and the agent cannot complete that step for the user.
Would AgentAdmit have prevented the Grok Bot incident?
Yes, had the apps involved integrated it. A finance agent granted read scopes only holds no post scope, so the report could not have been posted to Slack or anywhere else. If the owner had granted a post scope marked confirm each time, the send would have waited for his passkey approval of that exact call, which the agent cannot complete for him. The Slack connector and bank feed in this story do not integrate AgentAdmit today, which is why the control was missing.
See how apps give users scoped, per-action control over their AI agents.