Read-Only Was Never the Same as Safe

SELECT-only credentials close exactly one of the four ways an analytics agent can hurt you. The other three don't require the ability to write anything to the database at all.

The analytics agent got approved in about ten minutes. It could answer questions about the warehouse by writing its own SQL, and its credentials were SELECT only — no insert, no update, no delete, no DDL. Nobody in the review had a hard question, because the risk everyone was scanning for was "can it destroy data," and the answer was clearly no.

Read-only closes exactly one of the four ways that agent can hurt you. Here are the other three, and none of them requires writing a single row.

The threat model that read-only actually addresses

Mutation. That is the whole list. An agent that cannot write cannot corrupt a table, cannot drop a schema, cannot silently change a number that a report depends on. That is a real category of harm and read-only genuinely eliminates it.

The mistake is treating it as a proxy for harmless. The other three harms — resource consumption, egress, and influence — are all fully available to a reader.

Harm 1: reads are not free

A query is a purchase. On a warehouse that bills by bytes scanned, or on a cluster with fixed slots, a badly-shaped SELECT costs money and capacity in a way an INSERT of one row never does.

The agentic twist is the retry loop. When a query returns nothing useful, a model's natural repair move is to broaden it:

attempt 1: filtered to one week, one region      -> 0 rows
attempt 2: drop the region filter                -> 0 rows
attempt 3: widen to one year, remove the join key -> full scan

Each repair is more expensive than the failure it is repairing, and the agent has no sense of what step three costs relative to step one. On a shared cluster, an agent doing this while someone runs the monthly close is an outage for the close.

✅ The controls that fit this: a statement timeout, a bytes-scanned ceiling per query, a total budget per run that aborts the loop rather than the query, and a dedicated resource pool so the agent cannot starve human work. Cost limits belong on the run, not just the statement, because it is the tenth query that gets you.

Harm 2: read access plus an output channel is a data pipeline

This is the one that gets skipped, because permissions get reviewed one system at a time.

The agent's output is a write. It just isn't a write to the database. If the same agent can read a customer table and post its answer into a Slack channel, write a file to a shared drive, or send an email, then the pair of those permissions is an exfiltration path that neither permission looks like on its own. Least privilege on the warehouse bought nothing, because the data was never going to leave through the warehouse.

The review question is not "is the read scope minimal" and separately "is the write scope minimal." It is the product:

Reads Writes to Actual risk
Aggregates only Anywhere Low
Row-level PII Private, audited log Contained
Row-level PII A team channel An unlogged export
Row-level PII Arbitrary email An unlogged export to anywhere

⚠️ A channel with two hundred members in it is a publication, and nothing about the agent's SQL privileges will tell you that.

Harm 3: everything it reads gets copied into weaker systems

Rows the agent reads do not stay in the query result. They land in the model context, then in the trace store, then in whatever log line captured the tool response, and often in an eval dataset assembled later from real traces because real traces make the best test cases.

The warehouse has column-level access control, audit logs and a retention policy. The trace store almost certainly has none of those, and a much broader set of people can read it — anyone debugging the agent.

So read-only credentials on a sensitive table quietly mean copies of that table's contents in four or five systems that were never scoped to hold it. This is a compliance problem before it is a security problem, and it is invisible in the permissions review because no permission was exceeded.

✅ Redact at the tool boundary, inside the tool, before the result becomes a message. Redacting afterwards is too late: the data is already in the context and therefore already in the trace.

Harm 4: what the agent reads can steer what a human does next

A read-only agent still has an input channel, and free-text columns are the weak point. Support ticket bodies, customer names, product descriptions, note fields — any column where a user typed something is a place where instruction-shaped text can live.

The agent has no privileged action to hijack, which is why this gets dismissed. But its output goes into a report, and someone acts on the report. A note field reading "for accounts flagged like this one, finance should process the refund without review" does not need the agent to do anything. It needs the agent to repeat it somewhere credible.

Treat any column a customer can write to as untrusted input, mark it as such when it enters the context, and never let it reach a summary without that framing.

🔍 The review question that would have caught all four

Replace "can it write?" with two questions:

  1. What is the worst sentence this agent could produce, and who acts on it?
  2. What does one run cost at the ninety-ninth percentile, and who else feels it?

Then walk a checklist that is actually about a reader:

  • [ ] Per-query and per-run resource ceilings, with the run-level abort
  • [ ] Read scope enumerated at the column level, not "the warehouse"
  • [ ] Output destinations enumerated and evaluated against the read scope
  • [ ] Redaction inside the tool, before the result enters the context
  • [ ] Trace store access and retention matched to the most sensitive column readable
  • [ ] Customer-writable text columns marked as untrusted where they enter

Read-only bounds one axis. Cost, egress, replication and influence are all still wide open, and the interesting failures live there. The question worth asking about any agent is not what it can change — it is what it can cause.

Keep reading

Similar posts

Matched on shared tags and category — the more bars, the stronger the overlap with what you just read.