Engineering

Security and privacy for an agent that can act on your data

The threat model for an in-app agent is its tool set, not its microphone. The OWASP entries that apply, the injection path, and the controls worth building first.

VVoqal · Engineering9 min readPart of Safety

About this article

Most writing about assistant security starts at the microphone, which is the wrong end of the system. A microphone is an input. The thing worth securing is the set of operations the agent can perform once it has decided what you meant.

An agent with three read tools is a search box with a conversational interface, and its worst day is an embarrassing answer. An agent that can issue a refund, cancel a booking or move money is a piece of software that takes actions on a user’s behalf based on a model’s interpretation of ambiguous input. That is a different product with a different threat model, and the microphone is barely in it.

The model sits in the untrusted column on purpose. It is not malicious, it is credulous, and it reads attacker-writable text through the same channel as your instructions.

Start from the catalogue, not from the headlines#

OWASP maintains a Top 10 for LLM applications, currently the 2025 edition, and two of its entries describe most of what can go wrong with an in-app agent.

LLM01:2025 is prompt injection. The version that matters for an agent is the indirect one, described by Greshake and colleagues in Not what you’ve signed up for (February 2023). Their framing is the useful part: LLM-integrated applications “blur the line between data and instructions”, so an attacker can “remotely, without a direct interface, exploit LLM-integrated applications by strategically injecting prompts into data likely to be retrieved”. Their conclusion is blunt about severity, since processing a retrieved prompt “can act as arbitrary code execution, manipulate the application’s functionality, and control how and if other APIs are called”.

Translate that into your app. Your agent reads support tickets, product descriptions, merchant names, delivery notes, a field somebody typed into a form three years ago. Any of those is a place to write a sentence addressed to the model. The attacker does not need to reach your user or your microphone at all.

LLM06:2025 is excessive agency, which OWASP traces to three causes: extensions that include capabilities nobody needed, permissions wider than the downstream system requires, and autonomy without verification before a high-impact action. Their first prevention measure is stated plainly: “Utilise human-in-the-loop control to require a human to approve high-impact actions before they are taken.” They also note that monitoring and rate limiting cannot prevent excessive agency and can only reduce the damage, which is worth remembering the next time an alerting dashboard is offered as a control.

The Model Context Protocol specification says the same thing from the protocol’s side, in its Security and Trust and Safety section. Tools “represent arbitrary code execution and must be treated with appropriate caution”, tool descriptions “should be considered untrusted, unless obtained from a trusted server”, and hosts “must obtain explicit user consent before invoking any tool”. The spec also concedes that it cannot enforce any of this at the protocol level, which puts the obligation in your code.

The control that answers three threats at once#

Injection, excessive agency and forged speech all end at the same place. That is a reason to build it first, ahead of anything that detects an attack.

A confirm step is not a sentence in a prompt telling the model to ask first. It is a branch in your server code: tools that write are intercepted before execution, and what comes back to the client is a description of the proposed action rather than its result. The user sees an amount, a recipient and a date, and taps. Only then does the action run.

Why this holds where prompt instructions do not: a model that has been successfully injected will cheerfully ignore an instruction to confirm, because ignoring instructions is precisely what the attack achieved. A branch in code has no opinion about the conversation that produced the call.

An iOS screen where the agent has asked for an amount and then drawn a single confirm card for a 1,000 Egyptian pound payment link, awaiting the user's approval.
One card, one action, one tap. The card is drawn from the intercepted tool call, so what the user approves is the call that will run rather than a summary of it.

Two design rules make the difference between a confirm card and a dialog box people learn to dismiss. The card describes the specific call, with the actual arguments, so approving it approves something concrete. And there is exactly one card per turn, because a screen with three pending approvals trains the user to tap through all of them. The confirm card as a code boundary covers the implementation in detail, and what happens when an injected instruction reaches the spending path covers the adversarial cases.

Biometrics, tiered rather than sprinkled#

A biometric check is a stronger claim than a tap. It asserts that the person holding the device is the enrolled user at this moment, and it is enforced by hardware rather than by your code. It also costs a second and a small amount of goodwill each time.

Android’s guidance is unusually specific about where that cost is worth paying. Its biometric authentication documentation distinguishes keys with a validity window from auth-per-use keys, which require “the user to present either a biometric credential or a device credential each time your app needs to access data that’s guarded by that key”, and says these “can be useful for high-value transactions, such as making a large payment or updating a person’s health records”. The platform is telling you to tier. iOS has an equivalent hardware boundary in the Secure Enclave, where Apple documents that hardware keys derived from the device UID or GID “stay within the AES Engine and aren’t made visible even to sepOS software”.

In practice a small number of actions deserve a biometric and everything else deserves a tap. Our own deployment reserves it for a single operation, instant settlement, because it is the one that moves money to an external account. Reading a balance has no gate at all. Which actions deserve Face ID is the longer argument for drawing that line deliberately rather than by default.

Where voice actually changes the picture#

Spoken input is easy to forge. The US Federal Trade Commission has warned consumers that a scammer can clone a voice from a short clip taken from social media. That is a real problem for any system that treats a voiceprint as a credential.

It is not much of a problem for a system that never did. If speech only ever produces a proposed action, and the approval is a tap on a device that holds a hardware-bound key, then a perfect clone of the user’s voice buys an attacker the ability to draft something the user will decline. The security property comes from where the approval lives, not from detecting the forgery.

Liveness and synthetic-speech detection are worth having as a second layer, and they are an arms race by construction: every improvement in detection is a training signal for the next generation of synthesis. Architecture that removes voice from the authorisation path does not have to win that race.

What leaves the device, and what you keep#

The left column is the security argument. The right column is the privacy one, and it is the shorter list by design.

Privacy work on an agent is mostly subtraction. Send the audio or transcript the turn needs and nothing else. Scrub identifiers before anything reaches a log. Set a retention window short enough that you would be comfortable reading it out in a meeting, and delete on request without a ticket.

Treat recordings of a person’s voice as sensitive by default and design as though a regulator will ask. We are not going to summarise any jurisdiction’s law here, because a blog post is the wrong place to get that from and the old version of this page cited three intermediaries rather than a statute. The engineering rule stands without the legal citation: the recording you did not keep cannot be breached, subpoenaed, or mis-shared.

For governance framing, NIST’s AI Risk Management Framework, released 26 January 2023, organises this work into Govern, Map, Measure and Manage. It is voluntary and it is not a control list, which is exactly why it is useful when someone asks how you decided what to build first.

The order to build them in#

Build the confirm gate first, because three threats end there and because it is the control that keeps working after a model change.

Second, narrow the tool set. Every tool you do not expose is an attack you do not have to reason about, and OWASP’s excessive-agency guidance is a list of ways to expose fewer of them.

Third, bind the session to the device. A hardware key that signs each request means a captured request cannot be replayed from somewhere else, and a stolen token alone is not enough.

Fourth, tier the biometric onto the handful of actions that genuinely warrant it.

Fifth, minimise and expire the data. This is the one most often deferred, and the one an incident makes expensive.

Sixth, add detection. It is a real layer and it belongs last, because it is the only one whose value depends on staying ahead of an adversary.

Latency is the usual objection to all of this, and it is mostly misplaced: the gate costs a tap, while the seconds live in the cold connections and cache misses that have nothing to do with security. The security documentation covers how the confirm interception and the device key are wired in the SDK.

Sources#

Filed underSecurityAgentsPrivacyConfirmation

Next

How an action is gated, what the confirm step guarantees, and what leaves the device.

Read the security model

The rest of Safety

Open the cluster

Confirm-first actions, biometric tiering, scoped tokens and the audit trail you need before an agent touches money.

Elsewhere on the map