dbSDK

The lock is a read-only role

DB SDK is designed to read, not write. It should not store credentials. Treat every query — especially a model-generated one — as untrusted.

Read, not write

query() is a bounded read. Writes are never part of DB SDK.

In-memory credentials

Secrets are input, never persisted.

Untrusted queries

Prompts and SDK SQL checks are not a security boundary.

Assume the query is hostile

The dangerous case is a host that runs SQL it did not write: customer input, admin consoles, or a model. No single layer is enough.

  1. 01

    Queries are untrusted

  2. 02

    Credentials are powerful unless the customer restricts them

  3. 03

    A sanitizer or SQL classifier can miss an edge case

  4. 04

    A compromised host can use whatever role it stored

Four layers. One lock.

SDK and provider checks are extra. If the stored user can DELETE, a missed validation case is a write.

SDK

extra

Read-oriented API, default time and row limits. Fail closed when unsure. Not a security boundary.

await db.query()

Provider

extra

Engine-specific checks. SQL policy on the Postgres driver. Read APIs only on Firestore. Not a security boundary.

npm i @db-sdk/postgres

Runtime

extra

Timeouts, required or injected limits, abort signals, and bounded result payloads.

AbortSignal.timeout()

Database

the lock

The lock: a dedicated read-only role or IAM principal, restricted schemas, TLS.

GRANT SELECT

Allowed vs not allowed

If a statement cannot be shown to be a read, it should not run. That fail-closed rule is extra — not a substitute for a read-only role.

Allowed

  • Credentials

    In memory, supplied by the host

  • SQL

    SELECT / WITH … SELECT

  • Documents

    get / list / find

  • Results

    A bounded result set

  • Sessions

    Time out a slow query

Not allowed

  • Credentials

    Persist, log, or send to a third party

  • SQL

    INSERT, UPDATE, DELETE, DROP, ALTER, TRUNCATE, GRANT

  • Documents

    set / update / delete / writeBatch

  • Results

    Dump an entire table or collection

  • Sessions

    Hold an unbounded session

Who does what

If a host skips these, that is a host bug — not “DB SDK has write access.” Treat a DB SDK host like any BI or support tool.

Host must

  1. 01

    Encrypt credentials at rest

    Decrypt only on the server, for the duration of a test or query.

  2. 02

    Never send secrets to the browser

    Clients may see connection names and catalogs, not URLs or keys.

  3. 03

    Scope by tenant

    An agent or user may only use connections that tenant attached.

  4. 04

    Prefer a dedicated role

    Ask customers for a read-only user, not a superuser URL.

  5. 05

    Do not treat the SDK as a warehouse

    Avoid archiving full result dumps.

Customer should

  1. 01

    Create a read-only role

    SELECT only, or Firestore / IAM that can only read.

  2. 02

    Restrict schemas and collections

    Do not expose payroll or secrets tables if the product does not need them.

  3. 03

    Use TLS

    Do not disable SSL in production.

  4. 04

    Network-restrict if you can

    Allowlist, VPC, tunnel, or private link.

  5. 05

    Rotate and revoke

    Rotate credentials when people leave, and revoke access in the product when you disconnect.

Typical read-only roles

Prefer credentials that cannot write even if the SDK is wrong.

Postgres

readonly.sql
CREATE ROLE db_sdk_reader LOGIN PASSWORD '...';
GRANT CONNECT ON DATABASE app TO db_sdk_reader;
GRANT USAGE ON SCHEMA public TO db_sdk_reader;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO db_sdk_reader;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
  GRANT SELECT ON TABLES TO db_sdk_reader;

MySQL

readonly.sql
CREATE USER 'db_sdk_reader'@'%' IDENTIFIED BY '...';
GRANT SELECT ON app.* TO 'db_sdk_reader'@'%';

Firestore

readonly.yaml
title: DB SDK reader
includedPermissions:
  - datastore.entities.get
  - datastore.entities.list

How a query is checked

Default numeric caps will be chosen in implementation. Hosts should be able to tighten them.

Relational

Postgres first, then other SQL drivers

  • Reject statements that are not SELECT or WITH … SELECT
  • Reject mutation, DDL, and multi-statement batches
  • Parameterized queries — values are never concatenated
  • Row cap even if the query omits LIMIT / TOP
  • Statement timeout
  • Dialect details stay in the driver

Document

Firestore first

  • Call read APIs only
  • Collection from the catalog or an allow list
  • Limit required on every query
  • No write aggregations, $out / $merge, or write transactions
  • Sample for schema — do not download the collection

AI-generated queries

DB SDK does not call a model and does not take an AI API key. Model output is untrusted input.

  1. 01

    Use introspect() as context — do not give the model raw credentials.

  2. 02

    Pass the model output into query() as untrusted input.

  3. 03

    Never skip provider checks because “the model was instructed to only SELECT”.

  4. 04

    Keep the AI API key in the host; the SDK does not need it.

Credentials stay in memory

ProviderTypicalPrefer
PostgresURI or host / user / passwordCONNECT + SELECT only
FirestoreGoogle OAuth, then IAMdatastore get / list only, not Editor
Later driversURI or provider configEquivalent read-only role

Data flow

Nothing in this path should write to the customer database.

  1. 01

    Client

    Never sees the connection secret.

  2. 02

    Host

    Decrypts credentials, checks tenant access. A model may draft a query from the catalog.

  3. 03

    DB SDK

    Validate, then a bounded read-only query.

  4. 04

    Database

    Returns a bounded result. Nothing in this path should write.

  5. 05

    Client

    An answer and/or a small result table.

If a host is compromised

An attacker may read whatever the stored role can read. They should not be able to change data through DB SDK. Stolen credentials should still be read-only.

This project does not

  • Train models on customer data
  • Sell or share rows
  • Bypass RLS, grants, or Firestore rules
  • Require a public IP

A write that runs through query() is a vulnerability. The SDK authenticates as the principal you provided — it does not bypass RLS, grants, or Firestore rules.

Report privately

If you believe DB SDK can write, bypass read-only policy, or leak credentials, do not open a public GitHub issue with an exploit.