Menu
Blog How it works Use Cases
agentsh
Open-source runtime for AI agent security
Beacon
AI endpoint visibility and control
Watchtower
Enterprise control plane for agentsh and Beacon
Contact Us

AgentSH: A Policy Boundary on the Database Wire

AgentSH: A Policy Boundary on the Database Wire

Execution-Layer Security now covers one of the riskiest things an agent can touch: your database.


We built AgentSH on a stubborn premise: rules are not enforcement. A CLAUDE.md that says "don't touch production" is a suggestion. A system prompt that says "only run read-only queries" is a hope. Once an agent has a connection string and a reason, that text is no longer load-bearing. Enforcement has to live somewhere the agent can't talk its way past.

AgentSH already provides that boundary for files, processes, and network calls. The database proxy brings it to the data tier: AgentSH now classifies each statement an agent sends to PostgreSQL, evaluates it against policy, and decides — before it reaches your data. This is not another prompt, policy file, or advisory scanner. It's an inline enforcement point on the database wire.

Two failure modes, one connection

When an agent and a database share a blast radius, there are two distinct ways it goes wrong, and a useful control has to handle both.

The accident. The agent is doing exactly what you asked. It's iterating, exploring the schema, "cleaning up test data" — and somewhere in that loop it issues a statement that's correct in syntax and catastrophic in scope. A TRUNCATE meant for staging that hits prod. An UPDATE that lost its WHERE. No malice, just an autonomous process moving faster than your ability to review each step.

The attack. The agent is being steered by someone who isn't you. A prompt-injected instruction in a fetched page, a poisoned document, a malicious tool description — and now the agent is dutifully running a DROP because the text in its context told it to. The agent isn't compromised in the classical sense. It's working perfectly. It's just working for the attacker.

The uncomfortable part is that these look identical at the connection level. Both are a legitimate session sending a legitimate-looking query. You can't separate them by authenticating the connection harder, because the connection was never the problem. The statement is. Firewalls can see the path. IAM and access brokers can see identity. Database GRANTs can see roles and objects. But none of them reliably answer the agent-specific question: should this exact statement, from this exact agent session, run right now?

Why the tools you already run don't close this

You'll reach for controls you have. They each cover part of the gap:

There's a deeper distinction underneath. Human database-access tools — Teleport, Boundary, IAM DB auth — answer an identity question: who is connecting, from where, under what role? An agent is a delegated, probabilistic actor that may be operating under prompt injection or task drift, so identity isn't enough. The path needs to answer a second question: what is this agent trying to do right now? The proxy exists to answer that second question, and it's designed to sit on top of your GRANTs and roles, not replace them.

What shipped

The agent issues an ordinary PostgreSQL connection — same DSN, same drivers, same client libraries, no SDK to adopt and nothing to point at a different host. AgentSH transparently steers the connect through its proxy using the same connect_redirect mechanism it already uses to enforce outbound network policy: the TCP connect to the declared database upstream is rewritten to a per-session Unix socket where the proxy listens, and the proxy verifies the peer's process identity via SO_PEERCRED against AgentSH's session registry. Direct TCP egress to the database from anywhere outside the proxy's session is denied at the network layer, so the proxy isn't an opt-in step in the path — it is the path, for any process inside the governed tree.

From the database side, that path is an inline decision point: the proxy speaks PostgreSQL wire protocol v3, parses each statement into a list of effects, evaluates every effect against policy, and decides before anything reaches the database. The postgres and aurora_postgres dialects are fully supported, with redshift and cockroachdb in beta.

Each rule resolves to one of these decisions:

An important detail for writing policy: the database evaluator is order-independent. Unlike AgentSH's file and command rules, DB rules are evaluated collect-all — every covering rule is considered, and the most-restrictive verdict wins. Any matching deny wins, regardless of rule order. And coverage is strict: every object an effect touches must be covered by some rule, or the statement is implicitly denied. You don't sequence rules to stay safe; you just write them.

The controls, concretely

Because the proxy classifies statements into effects, policy can decide on the dimensions that matter for database safety:

Operation class. Reads, writes, and schema changes aren't the same risk. Policy can allow reads, approve writes, and deny schema-destroying operations like DROP and TRUNCATE — using operation tokens (READ, UPDATE, DELETE, DROP, the DANGEROUS bundle, and others) rather than three separate database roles.

Object and schema scope. Rules target specific schemas, syntactic object names, or catalog-resolved relations and functions. A READ on public.users can be allowed while writes elsewhere require approval.

Whereless mutations. require_where. An UPDATE or DELETE with no WHERE is the most common way agents (and humans) destroy data by accident. A rule with require_where: true covers a mutation only when it carries a syntactic WHERE clause — so you allow the bounded form and let strict coverage's implicit deny catch the whereless one. It's a syntactic guard, not a proof of selectivity: WHERE true satisfies it, so pair it with database-native constraints for real predicate enforcement.

Bulk export. A COPY ... TO that pulls a table out is how a "read-only" agent becomes a data breach. The classifier flags bulk-export effects as critical-tier, so policy can deny or gate them distinctly from ordinary reads.

Audit. Every decision is emitted as a structured event tied to the agent session and process context. By design, connection strings are parsed and their embedded credentials discarded at classification time — secrets never land in the event payload. Statement text logging is configurable (none, parameters_redacted, or full), defaulting to redacted. These events flow into AgentSH's telemetry pipeline and on to Watchtower, our commercial control plane. (A dedicated OCSF projection for database events is on the roadmap; today they use AgentSH's native DB event schema.)

A note on redirect

redirect is the most interesting capability: rather than only blocking a risky read, policy can express that it should be steered somewhere safe — a sensitive query pointed at a redacted view instead of denied outright. It is read-only by design: it will not reroute writes. Today the policy engine accepts and validates redirect rules, while runtime enforcement is next on the roadmap. We'd rather tell you that than imply your queries are already being transparently rewritten.

What it looks like in policy

These rules use the same fields and tokens as the proxy's own sample policy. A service is declared, then statement rules govern it:

db_services:
  appdb:
    family: postgres
    dialect: postgres
    upstream: db.internal:5432
    tls_mode: terminate_reissue

database_rules:
  # Reads are fine on appdb
  - name: app-read
    db_service: appdb
    operations: [READ]
    decision: allow

  # Bounded updates are fine; they must carry a WHERE to be covered at all
  - name: app-bounded-updates
    db_service: appdb
    operations: [UPDATE]
    require_where: true
    decision: allow

  # Deletes are riskier — cover only bounded deletes, and route them past a human
  - name: app-bounded-deletes
    db_service: appdb
    operations: [DELETE]
    require_where: true
    decision: approve
    message: "Agent wants to DELETE on appdb: "

  # Destructive schema changes and bulk export are off the table
  - name: app-deny-dangerous
    db_service: appdb
    operations: [CREATE, DROP, ALTER, TRUNCATE, EXPORT]
    decision: deny
    deny_mode_in_tx: terminate
    message: "Agent is not allowed to perform  on appdb"

  # Catch-all: anything the classifier can't read fails closed
  - name: catch-all-unknown
    operations: [unknown]
    decision: deny
    message: "Statement could not be classified. Failing closed."

You can check how a given statement would be judged without sending it anywhere:

agentsh policy db explain ./policy.yaml --service appdb --sql 'SELECT * FROM users'

Because evaluation is collect-all with any-deny-wins and strict coverage, the recommended posture is default-deny: allow the safe paths, approve the risky ones, and let everything uncovered fall to implicit deny.

What it governs today, and what's next

We'll be straight about the boundary, because the people who adopt execution-layer security are the people who distrust a pitch with no edges.

Two capabilities are coming that make the boundary even sharper. Runtime redirect will transparently steer a flagged read to a redacted view, turning "deny and let the agent improvise" into "succeed safely." And a credential broker will hold the upstream credential so the agent authenticates to the proxy, never to the database — taking the production secret out of the agent's hands entirely. Today the proxy governs what an agent can do, statement by statement; these extend it to govern what it can reach and what it ever holds.

Get it

AgentSH is open source (Apache-2.0). The database proxy is available now.

Agents need database access. Prompts aren't enforcement, and GRANTs are necessary but weren't designed to make agent-aware, per-statement decisions at runtime. AgentSH now puts a policy decision in the database path — so an agent can do the data work you asked for, statement by statement, under rules it can't argue with.

Pull the release, run an agent under AgentSH against your normal database DSN, and try to make it do something it shouldn't. Then tell us where it bites. That's how the last several releases got good.

← All posts

Built by Canyon Road

We build Beacon and AgentSH to give security teams runtime control over AI tools and agents, whether supervised on endpoints or running unsupervised at scale. Policy enforced at the point of execution, not the prompt.

Contact Us →
Learn the category: Execution-Layer Security → See examples: Use Cases →