Skip to content
All insights AI architecture for finance

Governing agent tool use in finance workflows

An agent that can call tools can move money. Here is the authorization, rate-limiting and action-validation layer we require before an agent touches a finance system.

4 min read #agentic#security#architecture
Financial services professionals working through an AI initiative

An agent that can call tools can move money, and the authorization layer decides whether it may. Before an agent touches a finance system we require four things around every tool: a scoped identity naming both the agent and the person it acts for, a policy check that runs on the tool server rather than in the prompt, per-action and per-window limits, and an append-only record of every attempt.

The model proposes; the tool layer disposes. The failure everyone pictures is the model saying something false. The failure that actually costs you is the model issuing a correct-looking transfers.create with the wrong counterparty, or retrying a payment three times because a timeout looked like a failure. A language model is a generator of plausible next steps, and a payment API does exactly what it is told. Nothing in the transformer knows that this particular POST empties an operating account at quarter-end. So the governance cannot live inside the reasoning. It has to sit on the wire between the agent and the system of record.

Identity and least privilege at the tool boundary

Start by refusing to let the agent inherit a human’s full entitlements. A support agent that reads a customer’s transaction history does not need the scope that initiates a refund, and neither of those needs the scope that changes a beneficiary. Model each tool as its own permission, not each system.

We give the agent a service identity of its own and pass the acting user as a separate principal on every request. The tool server then intersects two things: what this agent class is allowed to do at all, and what this specific user is entitled to do. A refund tool that a user could invoke by hand becomes callable by the agent only inside that intersection. This also fixes the confused-deputy problem, where the agent holds broad credentials and a manipulated prompt borrows them. If the agent’s own scope is narrow, a hijacked prompt has little to borrow.

Concretely, least privilege here means:

  • One credential per tool surface, minted short-lived, never a shared platform key.
  • Scopes expressed as verbs on resources (invoices.read, payments.initiate_below_1000), not coarse roles like finance_admin.
  • Read and write split into different tools even when the same API backs both, so a read-only workflow can never be granted write by accident.
  • Entitlement checks resolved against the same authorization service your human users hit, so there is one source of truth and one place to revoke.

Validate the action, not the sentence

The agent’s tool call is a claim, and you should treat it the way you treat any client input: untrusted until the server proves it safe. Validation belongs on the tool server or a proxy in front of it, because that is the only place a prompt injection cannot reach.

For a payment or ledger action we check, server-side, before anything executes:

  • Schema and type correctness, including that the amount is positive, in the currency the account actually holds, and within the precision the ledger uses.
  • Business invariants that the model has no reliable view of: the counterparty exists and is not on a sanctions or internal block list, the source account has cleared funds, the action does not breach an approval threshold that requires a human.
  • Point-in-time correctness of any figure the agent computed. If the agent summed an exposure to justify a limit increase, recompute it from the feature store as of the decision timestamp rather than trusting the number in the prompt.
  • Idempotency. Every mutating call carries a client-generated key so a retry, a duplicated plan step, or a network timeout that the agent misread as a failure cannot double-execute. Straight-through processing without an idempotency key is how one instruction becomes two payments.

Anything above a configured value routes to a human approver instead of executing. The threshold is policy, versioned in the same place as the scopes, so lowering it during an incident is a config change and not a code deploy.

Rate limits, budgets and the audit trail

Authorization tells you whether a single action is allowed. Rate limiting tells you whether the pattern of actions is sane. An agent stuck in a loop is not a security breach in the classic sense, but it will happily call payments.initiate forty times in a minute if a retry policy is wrong and nothing stops it.

We put ceilings on both frequency and cumulative value. A tool gets a per-minute call cap, and a mutating tool also gets a rolling monetary budget: no more than N transfers or X total value per hour for this agent identity, independent of whether each one passes authorization. Breaching a budget trips the agent into a degraded mode where it can read and draft but must hand every write to a person. This is the same false-positive budget logic you already run in transaction monitoring, applied to the agent itself as an actor.

The record underneath all of this is not optional. Every tool call, allowed or denied, writes an append-only event: the agent identity, the acting principal, the resolved scope, the exact arguments after validation, the decision, and the policy version that made it. That gives you lineage from a ledger entry back to the specific agent run and the prompt that triggered it. When a controller asks why a payment went out at 2am on the last day of the quarter, the answer is a query, not an investigation. It is also what makes drift visible: if the deny rate on a tool climbs week over week, either the model changed behavior or someone is probing it, and both are things you want to see before the reconciliation does.

FAQ

Should the agent authenticate as itself or as the human it acts for?

As itself, with a distinct service identity, and it should carry the human principal as a separate claim on every call. That way the tool server can apply both the agent's own scope and the acting user's entitlements, and the audit trail records both.

Where should action validation live, in the agent or in the tool?

In the tool, or in a proxy in front of it. The agent's own output is untrusted because a prompt injection can rewrite it. Balance checks, limit checks and idempotency have to run on the server that actually performs the action.

How do you test the guardrails without moving real money?

Run the agent against a sandbox that mirrors the production tool contracts and replays real reconciliation and limit scenarios. Keep an adversarial eval set of injection and over-scope attempts and score the deny rate before every release.

Working on something similar?

Tell us about your data and the workflow around it, and we will give you a straight read.

Book a 30-min intro call