Est.

Giving an Agent Read Access Without Giving It Write Access

The fix requires a read-only database role, not better instructions for the agent.

Correspondent · · 3 min read · Updated
Features · August 22, 2026 · 3 min read · 608 words
# Giving an Agent Read Access Without Giving It Write Access An agent needed to look up customer records to answer support questions. The database client library it was handed had one connection string and one role, and that role could write. Nobody had asked for write access. It came bundled with read access because that's how the credential had always been provisioned for every other service in the codebase, and an agent is not another service — it's a process that decides what to do next based on unstructured text, which is a very different trust boundary than a service calling a fixed set of endpoints it was coded to call. ## The credential was scoped for a service, not for a reasoning process A normal backend service has a fixed, auditable set of queries it can ever issue — whatever's in the code. Reviewing the code is equivalent to reviewing everything the service can possibly do to the database. An agent with a general-purpose database tool and a write-capable connection doesn't have that property. Its set of possible queries is whatever it can construct from context at runtime, which is a much larger and much less reviewable space. The tool description said "look up customer records." The credential behind the tool said "do anything a write-capable role can do." Those aren't the same commitment, and only one of them was actually being enforced. Nothing had gone wrong yet. That's the uncomfortable part of finding a gap like this — there's no incident to point to, just a permission boundary that was wider than the stated job, discovered by asking what the credential could do rather than what the agent had been observed doing. ## "It hasn't misused it" is not the same as "it can't" The natural response to finding this is to check the transcripts — has the agent ever issued a write? It hadn't. That's reassuring about behavior observed so far and says nothing about behavior under a prompt-injection payload embedded in a customer record it reads, a reasoning error under an unusual input, or a future change to the agent's instructions that widens its intended scope without anyone revisiting the credential underneath it. A permission boundary that's only as narrow as observed behavior isn't a boundary — it's a trend line, and trend lines break. ## The fix was provisioning, not prompting It would have been tempting to fix this by instructing the agent more firmly not to write, or by having it explain its reasoning before any database call so a human could review it. Both add friction without adding a guarantee — a sufficiently confident wrong instruction still executes as a valid, permitted write. The actual fix was provisioning a second, genuinely read-only database role and pointing the customer-lookup tool at that connection instead. Now a write attempt doesn't get caught by a smarter prompt or a more careful review step. It gets rejected by the database, unconditionally, before the agent's reasoning is even part of the equation. This is the same principle that's uncontroversial for human access — nobody gives a support rep production write access because they've only ever needed to look things up — applied to a process that, unlike a support rep, can be steered by text it reads as part of doing its job. The credential should describe the actual worst case the tool can produce, not the typical case it's expected to produce. If the honest answer to "what's the worst this tool could do" is broader than the tool's stated purpose, the tool's access is wrong, independent of whether anything has gone wrong yet.

More in Features