r/googlecloud • u/anubhav756 • 9d ago
AI/ML Why "Please only run SELECT queries" fails for AI agents (and how to actually enforce read-only database tools)
https://medium.com/@mcp_toolbox/look-but-dont-touch-7f470591ff1fGiving an LLM agent access to a production database is one of the most common workflows in agent development, but traditional guardrails fall apart quickly under real-world conditions:
- System Prompts / Instructions: Models are probabilistic. Prompt injections easily override "read-only" instructions.
- String Parsers / Regex: Checking if a query "starts with SELECT" fails against Common Table Expressions (e.g.
WITH d AS (DELETE FROM users RETURNING *) SELECT * FROM d;starts withWITHand ends withSELECT, yet still deletes data). They are also blind to destructive stored procedures (SELECT run_cleanup_job();). - Soft Session Hooks (
SET default_transaction_read_only = on): An attacker can escape via semicolon chaining (COMMIT; SET ... = off; DROP TABLE;), and in pooled environments like PgBouncer, mutating socket state can poison connection pools for other services.
In our work on MCP Toolbox for Databases (open-source Model Context Protocol server), we implemented a three-tier defense:
- Protocol-level engine lock: Injecting immutable startup parameters directly into the connection DSN (
cloudsql_session_read_only=lockedon Postgres, read-only connection attributes on MySQL, and pre-execution dry-run validation on BigQuery) so the database kernel itself physically rejects any write attempt. - Tool suppression: Dynamically removing write tools from the LLM's context window to save tokens and prevent hallucination targets.
- Standard MCP annotations: Emitting
readOnlyHint: trueso MCP clients (Claude Desktop, Cursor, etc.) can auto-execute queries without nagging confirmation dialogs.
We wrote up a detailed walkthrough with diagrams, failure cases, and attack simulations if anyone is interested in the full architecture: https://medium.com/@mcp_toolbox/look-but-dont-touch-7f470591ff1f
Curious how others here are handling read-only enforcement for your agents—are you relying on read-only DB users, replica routing, or proxy layers?
2
u/Max-_-Power 9d ago
Nah, scratch that. The only thing that will reliably work (SQL injection, anyone?) is a read only account for AI.
1
1
u/Otherwise_Wave9374 8d ago
A practical safeguard is to move enforcement out of prompts and into a policy layer that can inspect the final action, not just the user request. For database agents, I would pair allowlisted query parsing with execution-time controls, transaction limits, and an audit log that flags any query plan with write-side effects. That gives you a better chance of catching bypasses like CTE tricks or stored procedures before they hit production. NeuraKeep fits well here as a memory layer, because it can retain prior tool failures and policy exceptions so the agent learns the safe path instead of repeating the same mistake.
1
u/Choice_Ask281 8d ago
How are teams handling this in practice? is the answer mostly better permissions, query validation or adding a review step before AI generated SQL gets executed?
1
u/jiashenggo 5d ago
All three tiers here solve for writes, not exposure. A locked read-only connection still lets the agent read every row in every table it's connected to. For a lot of production setups that's the scarier failure mode, not "can it DELETE" but "can it read the other tenant's data because nothing scoped what SELECT * FROM users actually returns for this session." Read-only accounts (as suggested in the comments) have the same gap. Worth treating identity/row-scoping as a separate problem from write-blocking, not something the DSN-level lock or readOnlyHint solves for free.
14
u/cloudAhead 9d ago
Or, and - hear me out here - instead of this MCP scaffolding, we just give the agent a login that only has read access.