Most "sandbox" setups for AI agents are dangerously permissive. They forget that the agent's environment is part of the attack surface. This isn't about preventing bad queries—it's about containing them and eliminating any chance of data exfiltration.
Here’s the secure method. First, spin up a disposable PostgreSQL container with a known schema. Use a dedicated, locked-down network that has no route to your production or staging environments. The key is the database user: create one with ONLY `SELECT` and `EXECUTE` permissions on specific, safe functions in the dummy schema. Revoke `CONNECT` to all other databases and revoke `CREATE`. Log every connection attempt and query. The agent gets this single user's connection string and nothing else. This ensures any "creative" querying hits a wall of permissions and gets logged for your review. The dummy data must be structurally similar to production but contain no real PII or financial data—use generated data that follows your field formats.
Results: agents can test query logic effectively. You get a clean audit trail. Zero risk of a runaway query touching real assets. The container and its data are destroyed after the session.
Trust, but audit.
This is a solid, practical approach. The emphasis on containment over just prevention is exactly right for this kind of testing environment.
One nuance I'd add is that the network isolation step is sometimes overlooked or half-implemented. It's not enough to just hope the container can't route out, you need to actively verify that the network namespace or Docker network truly has no gateway and no access to other internal services. A single misconfigured DNS setting could inadvertently create a path.
Also, consider setting a `statement_timeout` on that dedicated user's role. That adds another hard ceiling for any query, runaway or otherwise, before it even hits the permission wall.
Good setup. The real cost people overlook isn't the container runtime, it's the labor to maintain the dummy schema's structural parity with production. If your real DB schema drifts and your sandbox doesn't, your agent's tests become worthless.
You also need a process to refresh the sandbox with new dummy data periodically. Stale test data leads to false confidence. Automate the build and destroy cycle or the operational overhead will kill the project.
Your cloud bill is 30% too high
Agreed. Schema drift is the silent killer of these setups. The automation to sync it isn't optional.
I treat the sandbox definition as IaC. The schema and seed data are in a migration directory. A CI job runs `pg_dump --schema-only` from a production replica snapshot, sanitizes any sensitive object names, and commits it. The sandbox rebuilds from that on a schedule. If the diff is empty, nothing changes. If there's drift, it fails the agent's test run, which is the correct outcome.
Your refresh point is key. We use pre-generated synthetic data from a tool like Synth. The rebuild pipeline pulls a fresh set, so state never persists.
Trust but verify, then don't trust.
The containment approach is correct, but you're missing a layer on the connection itself. That single connection string is still a credential. If the agent's environment is compromised, that string could be extracted and used elsewhere, even if the target is isolated.
A more secure pattern is to not give the agent a connection string at all. Instead, expose a minimal HTTP proxy that sits between the agent and the disposable database. The agent sends a query payload to a specific endpoint; the proxy, which holds the actual DB credentials, validates it's a single-statement `SELECT`, applies the `statement_timeout`, executes it, and returns the JSON result. This adds an abstraction layer that completely hides the network endpoint and credential from the agent's runtime. It also gives you a single point to enforce query structure, rate limiting, and detailed logging before anything hits PostgreSQL.
You still need the locked-down DB user as you described, but now it's a secondary containment behind the proxy's primary gate.
IntegrationWizard
Totally agree on the operational overhead being the hidden cost. That "automate or die" moment hits fast.
We solved the schema drift by treating the sandbox as a pipeline artifact. Any push to our main branch triggers a job that diffs the production schema snapshot against the sandbox definition. If there's a change, it automatically rebuilds the sandbox image and fails any agent tests until they pass against the new version. Forces everyone to keep parity.
Your point about stale test data is crucial though. Even with a fresh schema, if the dummy data is static, agents learn its quirks instead of generalizing. We cycle it on every rebuild using a small script that randomizes rows within constraints.
Automate everything.