SERVICE 04 · Agent engineering

AI Agent Development

An agent is software with keys to your systems. We build them the way we would want to find them on a test: one identity of their own, the narrowest tool permissions that still do the job, a written set of cases they must pass before release, and a log of every run.

The boundary is the product An isometric view of a production agent. The agent runs inside a dashed authorisation boundary as its own service principal, with two scoped tools inside the boundary: a read-only one and a write tool with a capped amount. A destructive tool sits outside the boundary, marked refused. AUTHORISATION BOUNDARY agent, own principal read_orders issue_refund capped delete_customer refused
Fig. 2 · The same boundary seen as an estate. The agent runs as its own service principal inside the dashed perimeter with two scoped tools; the destructive tool sits outside it, refused.
What this is

Not a chatbot. A process with credentials.

The agents we build read from systems you already run, decide what to do next, and call tools that change state: writing a record, moving a file, issuing a refund, opening a ticket. The interesting engineering is not the conversation. It is the list of things the agent is allowed to call, what happens when a call fails halfway, and who finds out.

Most of the work in a build is unglamorous: the tool manifest, the retry and idempotency rules, the cases it must pass, and the decision about which actions a person still signs off. We would rather spend four weeks there than ship something that looks impressive in a meeting and surprises you in week six.

We will not ship an agent with write access to a system where nobody can tell us what it should refuse to do.

// Settled during scoping, not after the first incident
Evaluation

The cases are written before the agent is.

An agent without an eval suite is a demo. It passed once, in front of you, on an input somebody chose. The suite is how you know whether today's change broke last month's behaviour.

Sometimes the suite says no. If the agent cannot clear the cases at a rate you can live with, we tell you before the build instead of after it, and occasionally the honest recommendation is a few hundred lines of deterministic code with no model anywhere in the loop.

Authorization

The boundary is the product.

Prompts are instructions. Permissions are enforcement. Anything the agent must not do gets written where the model cannot argue with it.

01

Its own identity

The agent gets a service principal of its own, never a human's session or a shared key. Its actions are attributable to it, and revoking it costs one admin action rather than a password reset for a person who is on leave.

02

Smallest permission that works

Each tool gets the narrowest scope that lets it finish: read limited to the records in question, writes limited to specific fields, no standing administrative role because it was quicker during the pilot.

03

Validation outside the model

Tool arguments are checked by code before execution: allow-listed destinations, bounded amounts, typed identifiers. The model proposes the call; something deterministic decides whether it runs.

04

Checkpoints on what cannot be undone

Deleting, paying, sending externally, changing an entitlement. These stop for a named human with the proposed action and the reasoning in front of them, until you have the run history to justify moving a particular one behind the line.

05

Budgets that end the run

Caps on steps, tool calls, tokens and wall-clock time per run. An agent in a loop is a cost event and a load event at the same time, and the ceiling belongs in the runtime, not in a dashboard you read on Monday.

06

A tested way to stop it

One switch that halts new runs, one that revokes the agent's credentials, and a rehearsal that proves both work with someone else on the keyboard. We write down how long a drain takes in practice.

Agent authorization boundary An untrusted user message and an untrusted retrieved document reach an agent that runs under its own service principal. A validation layer written in ordinary code checks every tool argument before execution: two scoped calls pass, and an instruction injected through the retrieved document, aimed at a destructive tool, is refused at the boundary. A run log records every step. UNTRUSTED INPUT — BOTH SOURCES User message from the ticket queue class: untrusted no standing privileges Retrieved document kb/refund-policy v14 class: untrusted carries injected text AGENT RUNTIME Refund triage agent OWN PRINCIPAL principal: svc-agent-ops never borrows a user session VALIDATION — ORDINARY CODE Tool-argument check plain code, outside the model TOOLS — SCOPED, NOT GENERAL read_orders scope orders:read READ-ONLY issue_refund one order · amount capped WRITE · CAPPED delete_customer irreversible · human checkpoint REFUSED RUN LOG appended by the gate, not by the model t0 trigger orders.flagged #8831 actor svc-agent-ops t1 context retrieved kb/refund-policy v14 sha 9ab1c0 class untrusted t2 read_orders order=A-2291 validate pass r03 1 record returned t3 issue_refund order=A-2291 amount=40.00 validate pass r11 refund queued t4 delete_customer id=* src retrieved doc validate REFUSED r12 wildcard arg r19 checkpoint req no call made t5 run closed 2 calls 1 refusal user turn injected instruction rides in proposes a tool call tries delete_customer(id=*) REFUSED only checked calls run
Fig. 1 · An injected instruction arriving through retrieved content, refused at the validation layer before it reaches a destructive tool. Every call is appended to the run log by the gate, not by the model.
Pre-release testing

We attack the agent before you hand it your data.

The same people who test other companies' LLM applications test ours, against the failure modes that actually show up rather than the ones that sound frightening.

01 / Injection through content

Instructions arriving as data

Text in a retrieved document, a support ticket, a filename, a web page the agent fetched. We plant directives in each channel the agent reads and check whether they change its tool calls.

OWASP LLM01
02 / Tool abuse

Calls outside the intended shape

Arguments the schema allows but the business does not, chained calls that assemble a privileged action out of unprivileged steps, and the same destructive call replayed.

OWASP LLM06
03 / Exfiltration

Data leaving through the context

System prompt and credential recovery, one tenant's records surfacing in another's answer, and outbound tools used as a channel to send what the agent was shown.

OWASP LLM02
04 / Confident wrong answers

No path to say it does not know

Questions with no supporting source, documents that contradict each other, and records the agent was never given. If the only option encoded is to answer, it will answer.

OWASP LLM09
05 / Retrieval integrity

What the index will accept

Who can put a document in front of the agent, whether permissions follow a record into the index, and what a poisoned or stale chunk does to the answer.

OWASP LLM08
06 / Unbounded consumption

The run that never ends

Inputs that drive recursive planning, prompts that expand each turn, and the cost curve of a single adversarial request against the caps we set.

OWASP LLM10

Identifiers refer to the OWASP Top 10 for LLM Applications. Citing a public list is not accreditation and we claim none from OWASP; we name the categories so you can check our coverage against something that is not our own marketing.

Operations

A run you can reconstruct six months later.

RECORD 01

Trigger

What started the run, which identity asked, and the exact input it received.

RECORD 02

Context

Which documents and records were retrieved, with versions, so the same context can be rebuilt.

RECORD 03

Calls

Every tool call in order, with arguments, result, and whether validation rejected it.

RECORD 04

Outcome

What the agent returned or changed, and where a human approved or overrode it.

RECORD 05

Cost

Tokens, tool calls and latency per run, so the unit economics are a number and not a feeling.

RECORD 06

Retention

How long each of the above is kept, where it lives, and who can read it.

Logs with personal data in them are a disclosure risk of their own. We agree what gets redacted at write time before the first run, rather than discovering the problem during a privacy review.

What we decline

Work we turn down, in writing, before it starts.

Agents fail in ways that are hard to walk back. These are the shapes we have decided not to take on.

No write access without a defined refusal

If nobody in the room can state what the agent must never do, there is nothing to build a boundary against. We will build the read-only version and wait.

No agent judging a person's outcome alone

Hiring, credit, discipline, benefits, access revocation. A model can prepare the file and surface the evidence; a named person decides and signs.

No pilot straight onto production data

The first runs happen against a copy, or against production with every write disabled and the proposed actions logged for comparison. Shadow mode first costs a fortnight and settles the argument with evidence.

No agent where a script would do

If the task is deterministic, we will say so and quote the smaller job. A model in the loop adds non-determinism, inference cost and a new attack surface, and it should earn all three.

Why us

We test other people's agents for a living.

LLM applications are one of the nine surfaces on our penetration testing scope. The findings we write for other companies are the reason this page talks about identities, tool argument validation and run logs rather than about what AI can do.

It also means the build and the test are not the same pair of eyes when you do not want them to be. Where we built the agent, we will say so plainly in the report, and you are free to have the boundary tested by someone else entirely. We will hand them the tool manifest and the eval suite.

See how we test →

Every finding we write about someone else's agent is a line in our own build checklist.

// Penetration testing → engineering, same team
Before you ask

Questions we get on the first call.

Which model do you build on?

Whichever one your legal and procurement teams have already cleared, hosted wherever your data is allowed to go. The model is a configurable dependency in what we build, not the architecture. The eval suite is what makes swapping one a decision with evidence behind it rather than a leap.

How long until something is running?

For a single agent with a narrow tool set, expect a week on cases and the tool manifest, three to five weeks of build and evaluation, then shadow mode against real traffic with writes disabled before anything acts. We would rather tell you that number than a shorter one we would then have to defend.

What do you need from us to start?

One owner who can say what the agent must refuse, access to a non-production copy of the systems it will touch, real historical examples of the task including the ones that went wrong, and written authorization for any tool that can write. Missing the first of those stops the engagement, not the last.

Do you operate it afterwards, or do we?

Either. If you take it, you get the code, the tool manifest, the eval suite, the baselines and the runbook for the stop switch, and we will sit with your on-call team while they rehearse it. If we operate it, the same artifacts exist and you can read them whenever you like.

Ours just answers questions from our documents. Does any of this apply?

Retrieval is where injected instructions arrive, and permissions in the index are where one team reads another team's records. A read-only assistant has a smaller blast radius, not a different set of problems. The eval suite is usually shorter and the boundary work is mostly about who can put a document in front of it.

Can you fix an agent somebody else built?

Often. The first week is an assessment: the tool permissions it actually holds, whether runs are reconstructable, and an eval suite built from your own history so there is a baseline to improve against. Sometimes the answer is that the boundary has to be rebuilt before the behaviour is worth tuning.

Related

The rest of the same team.

Engage

Tell us the task, and what the agent must never be allowed to do.