Safe agent ↔ database access · concept

Let your agent access your
production database.

maskdb.ai turns any PostgreSQL database into a read-only REST API for AI agents. Your agent connects with a dedicated token instead of the real password, you control exactly which columns it can and can't read, and sensitive columns are masked before a single byte leaves the proxy. Every query an agent makes is audited.

dedicated token, not your password you choose readable columns sensitive columns masked every query audited
The problem

Giving an agent a database is risky two ways

AI agents increasingly need to read production data — but the two obvious ways to grant access both leak something you cannot take back.

🔑 Credentials leak

Handing an agent a raw connection string exposes the real host, user, and password. Once it lands in a prompt, a log line, or a tool call, the keys to the whole database are out — and rotating them breaks everything downstream.

🫥 Sensitive data leaks

Even with read-only access, one SELECT * pulls emails, phone numbers, tokens, and PII straight into the model's context — where it gets summarized, cached, and potentially memorized.

How it works

One gateway in the middle — nothing installed on your DB

maskdb.ai holds the real connection. The agent only ever speaks a structured REST API, authenticated by a scoped token. Every result passes through the masking layer on the way out. You point it at an existing read-only connection string — no extensions, no views, no schema changes.

🗄️
PostgreSQL
untouched ·
real creds stay here
🛡️
maskdb.ai
compile + mask + auth
🤖
AI Agent
structured REST
+ token · read-only
All safety lives in the proxy → the database is never modified and never sees the agent's token.
Capabilities

What the proxy does

01

Structured queries, no raw SQL

Agents send a JSON query — table, columns, filters — never a SQL string. With no expression surface to exploit, the whole class of substring() / row_to_json / oracle bypasses simply doesn't exist.

02

Token-scoped & read-only

Each API token is read-only by design and can be scoped, rotated, and revoked independently. The agent never sees the database password, host, or network.

03

Column-level masking

Configure which columns to redact, hash, or partially reveal. Masking is applied as the query is compiled, so raw values never cross the wire — and masked columns can't be filtered on.

Setup · control plane

Two planes, two tokens

An admin token provisions; an agent token queries. The control-plane API below is also exactly what the web console runs on. The whole flow is three steps.

01

Self-register

One API call returns an admin_token — instant, no human gate, abuse-controlled only. An agent can bootstrap itself.

02

Add a DB + set masking

Register a database by {name, connection_string}, then set one masking baseline per column. This is the single place masking is configured.

03

Mint agent tokens

Issue read-only agent_tokens scoped to a set of DBs. Each inherits that DB's masking baseline. Revoke any token anytime.

POST
/v1/accounts
Self-register → returns the account's admin_token.
POST
/v1/databases
Add a DB by name + connection string (write-only, encrypted).
GET
/v1/databases/{db}/schema
Raw, unmasked schema — to decide what to mask.
PUT
/v1/databases/{db}/policy
Per-column enabled + mask strategy. The DB baseline.
POST
/v1/agent-tokens
Mint a read-only token scoped to a set of db_ids.
DEL
/v1/agent-tokens/{id}
Revoke a token instantly.
PUT /v1/databases/{db}/policy — the one masking baseline
# Authorization: Bearer mk_admin_…
{
  "tables": [{
    "table": "users",
    "columns": [
      { "name":"id",      "enabled":true },
      { "name":"email",   "enabled":true,  "mask":"email"  },
      { "name":"api_key", "enabled":true,  "mask":"hash"   },
      { "name":"ssn",     "enabled":true,  "mask":"redact" },
      { "name":"notes",   "enabled":false }
    ]
  }]
}
# mask: none | hash | redact | email | null
The API · data plane

A small, structured surface

What the agent token uses. Every capability is its own endpoint backed by a fixed, parameterized query — never agent-supplied SQL. A token can span multiple DBs, so each endpoint is db-scoped. Agents introspect the schema, then build queries against it.

GET
/v1/databases
List every DB this token can reach.
GET
/v1/databases/{db}/tables
List the tables the token can reach in a DB.
GET
/v1/databases/{db}/tables/{t}/schema
Enabled columns + per-column masked / filterable flags.
GET
/v1/databases/{db}/tables/{t}/indexes
Index name, columns, uniqueness, method, validity.
POST
/v1/databases/{db}/query
Structured SELECT / FROM / WHERE with a boolean DSL.
POST /v1/databases/{db}/query — request
# Authorization: Bearer mk_agent_… — no host, no password
{
  "table": "users",
  "select": ["id", "name", "email", "plan"],
  "where": {
    "and": [
      { "col":"status", "op":"eq",  "value":"active" },
      { "or": [
        { "col":"plan",    "op":"eq",  "value":"pro" },
        { "col":"credits", "op":"gte", "value":100 }
      ]}
    ]
  },
  "order_by": [{ "col":"id", "dir":"asc" }],
  "limit": 100, "offset": 0
}
response — masked
{
  "rows": [
    {
      "id": 1042,
      "name": "Ethan Zhang",
      "email": "e***@vm0.ai",
      "plan": "pro"
    },
    { /* … */ }
  ],
  "masked": ["email"],
  "page": { "limit":100, "offset":0, "returned":37 }
}
Column masking

You decide what the agent is allowed to see

Masking is set once per column when you register the database — a single baseline every agent token inherits. There's no per-token override to get wrong: if a column is masked, it's masked for every agent that touches that DB.

Raw row — in the database
idemailapi_key
1042ethan@vm0.aisk_live_9f3a2b…
1043lancy@vm0.aisk_live_77c1de…
What the agent receives
idemailapi_key
1042e***@vm0.ai••••••••
1043l***@vm0.ai••••••••

Mask strategies mix per column: full redaction for secrets, partial reveal for emails and phones, deterministic hashing to keep values joinable without exposing them, or drop to omit the column entirely.

Why it matters

Two guarantees, by construction

🔐

The real password never leaves the proxy

Agents authenticate with disposable, read-only tokens. Compromise one and you revoke one token — the database credentials, host, and network stay invisible and intact.

🧼

Sensitive columns are masked at the source

PII and secrets are redacted as the query compiles, before serialization. Raw values never reach the model's context, logs, or any cache it might write to — and can't be reconstructed through a filter.