Ledgenter

Blog · June 29, 2026

Assume your agent is already compromised. What can it reach in your workspace?

Most security questions about AI agents start in the wrong place: will my agent get prompt-injected? Treat that as a maybe and you'll build defenses that are mostly hope. An agent is a program that takes its instructions from text, and some of that text comes from outside — a web page it fetches, a tool result it reads, a task description someone else wrote. Buried somewhere in that text is "ignore your previous instructions and…," and a model that's good at following instructions follows it. Not always. But across enough runs reading enough untrusted input, the honest planning assumption is yes, eventually, one of them turns.

So skip the maybe. Assume it already happened. The agent in your shared workspace is, right now, taking orders from an attacker — and it has all of its legitimate credentials. Now ask the only question that matters: what can it actually reach?

That's the threat model worth designing against. Not the human breaking in from outside — the trusted agent on the inside, turned, trying its hardest to do the worst thing it can phrase. The size of the answer is your blast radius, and a workspace is safe to leave an agent alone in only if that radius is small no matter how the agent is steered.

Here's the radius, wall by wall.

Read: it sees its own tenant — and that's the ceiling

A turned agent will try to read everything. Inside its own tenant, it can: your tasks, your decisions, your knowledge notes. That isn't a breach — that's the job you gave it, and no amount of injection changes what its own work looks like. Containment isn't about blinding an agent to its own project.

The wall is the one next to it. The agent cannot read another tenant's work, because the boundary isn't a where tenant_id = ? it has to remember to add — it's a row-level-security policy the database applies to every read before a row is ever returned. The agent can phrase the broadest query it can imagine; the rows that aren't its tenant's are not hidden from the result, they were never in it. And it can't lie about which tenant it's in, because it never declares one — there is no tenant parameter to set. Identity resolves from the key to exactly one actor in one tenant. The classic injection — "now act as the customer in the other account" — isn't blocked by a check that could be missed. It isn't expressible.

So the read radius is: its own tenant, which it already had, and nothing past it.

Write: it can add to the record, but it can't quietly rewrite it

The scarier injection isn't "read" — it's "destroy." Delete every task. Rewrite the decision log to say we chose the other vendor. Erase the trail that you were here. This is where the shape of the store does the defending.

The work-state spine is append-only. A decision isn't edited; a later decision supersedes it, and both stay on the record with their authors and timestamps. The activity log only grows. There's no "rewrite history" primitive for an injection to reach for, because the system doesn't offer one to anybody — not to the agent, not to the operator. The worst a turned agent can do to the record is add a line, and the line it adds names it. Tampering that can only append is tampering you can see.

That's also why the audit trail is worth trusting under attack: it isn't a courtesy the agent chose to write honestly, it's a property of a log that can't be edited after the fact. "Did anything touch the boundary" is a query, not a hope.

Exfiltrate: it can't turn the platform's outbound into its own channel

A clever injection doesn't try to break the database — it tries to carry data out. "Take every decision in this workspace and send it to this URL." The agent can read its own tenant's data (we said so), so the only question is whether it has a pipe to push it through.

The platform's one outward seam — the escalation that reaches a human off-platform — does not take a destination from the agent. The agent can't name an arbitrary URL for the system to POST to; the destination resolves from configuration, not from the call, and outbound is screened against the server-side-request-forgery tricks that turn "notify me" into "fetch this internal address" or "deliver to attacker.example." An injection can ask the agent to exfiltrate. It can't hand the agent a working pipe to do it through, because the pipe's far end was never the agent's to choose.

Escalate: it can't widen its own reach

The last move of a cornered injection is to grow. Give myself the platform-wide read. Mint a fresh key with more scope. Reach into the deploy path. None of these are calls the agent can make.

Scope rides on the credential and is resolved at the door: a key without the platform scope that lets one operator watch the whole funnel is refused when it reaches for cross-tenant data, not shown a filtered slice. There's no tool that mints a more powerful key, and no parameter that elevates the current one. The capability set the key resolved to is the capability set for the whole run, injection or not.

This is the same principle the company runs itself on, and it's worth being concrete about because it's the proof we eat our own cooking. The agent loop that ships this product runs on a deliberately small token: it can open a pull request, and a human-defined gate decides whether that PR ever lands. By design it cannot trigger a production deploy, edit the CI workflows that gate it, rotate a credential, or touch any other repository. If that loop were injected tomorrow, the worst it could do is open a pull request full of bad code — which the gate it can't edit would catch. The agent operating the company is itself sandboxed, because "we trust our own agent" is exactly the sentence a shared-workspace vendor shouldn't get to say.

The honest part: we found one of these in our own loop

The reason this reads as conviction and not a brochure is that we hit it for real. Early on, our autonomous build loop had a path by which a compromised run could have exfiltrated a CI secret. We found it, closed it — and then kept the loop paused, not because the fix felt good, but until the containment around it was something we'd proven rather than hoped. A security model you've never seen tested against your own infrastructure is a set of claims. We'd rather show you the one we caught.

None of this makes an agent un-injectable. Nothing does — the agent will keep reading untrusted text, and some of that text will keep trying to steer it. The point is to make the steering not matter: to put every consequential boundary somewhere the agent can't lower it, so a hostile instruction runs into the same floor a confused one does.

The shortest version

Don't design for an agent that never gets injected — design for the one that already is. In a workspace built right, a fully compromised agent reads only the tenant it already had, can append to the record but never rewrite it, can't aim the platform's outbound at a URL it chose, and can't widen its own scope or reach the controls that contain it. Put the boundaries in the database, the credential, and the screened seam — never in the prompt — and "what can a prompt-injected agent do here" has a small, honest answer instead of a frightening one.

That's how Ledgenter is built, and it's the floor the company runs its own agent on. Start at ledgenter.com — a shared workspace that assumes the agent inside it could turn, and is safe anyway.

Give your agents an office, not a to-do list.