Skip to main content
AI coding agents regularly need real credentials — an API token to call GitHub as you, a key to hit your billing provider, a token to deploy. The path of least resistance is to paste the secret into the chat, but then the value lives in the model’s context, the transcript, and your provider’s logs forever. A secrets vault backed by an encrypted Turso database lets an agent use a secret without ever seeing its value: the secret is injected into a child process, the command runs, and the output is scrubbed before the agent sees it. This guide covers the schema, the encrypted connection, and the queries for a local secrets vault that an agent can use but never read.

Schema

The vault uses two tables: one for the secrets themselves, one for an append-only audit log.

How it fits together

  • secrets stores each credential keyed by name. The value column holds the secret itself and is only ever read to inject into a child process, never returned to the agent. The metadata columns (provider, account, environment, access, tags) describe a secret without revealing it, so an agent can reason about “the production database token” by its attributes.
  • audit_log is an append-only record of every use: which secrets were injected, the command, the working directory, the exit code, and the outcome (ran or denied).

Connecting

The vault is a single encrypted database file. Turso encrypts every page at rest when you pass a key at connection time, and multiprocess_wal lets several processes (a couple of agent sessions plus a CLI) open the same file safely:
hexkey is a 64-character hex string. Where it comes from is up to you. You can derive it from a passphrase with scrypt (and never store it), unwrap it from the OS keychain, or fetch it from a cloud KMS. Turso only needs the key at connect() time; the storage layer is identical regardless of the source.

Storing a secret

Upsert by name so rotating a value keeps the existing metadata:

Listing without exposing values

The query an agent is allowed to run simply never selects the value column:
This returns secret names and attributes — enough for an agent to pick the right credential — while the value never leaves the database.

Using a secret

To actually use a secret, read its value, inject it into a child process as an environment variable, run the command, and scrub the value out of the output before returning it:
The injection and scrubbing happen in application code, not the database:
Scrubbing captured output is not a sandbox. A command that can read a secret can always leak it on purpose (write it to a file, send it over the network). What the vault guarantees is narrower and still useful: the model never receives the value, and a careless echo $TOKEN gets redacted. The secret only ever lives in the encrypted file and the short-lived process that used it.

Auditing every use

Record each access as a row, and update the secret’s last_used_at:
“Who used the production key, when, and for what” is then an ordinary query:

Key design points

  • Encrypted at rest, for free. Turso handles whole-database encryption (AES-256-GCM, or one of the faster AEGIS ciphers). The vault never touches a cipher or manages page encryption — it derives a key and hands it to connect().
  • No coordinating daemon. multiprocess_wal lets each agent session and CLI invocation open the same encrypted file directly, so the database is the shared state instead of a long-running server you have to keep alive.
  • The value never appears in a list. Listing is a SELECT that omits the value column; the agent sees names and attributes only.
  • Fail closed. An unknown secret name aborts before the command runs, rather than executing with a missing credential.
  • Auditing is just a table. Every use is an INSERT; reporting on it is a SELECT you can export or alert on.

Example

keymaxxer is an MCP server that implements this pattern as an encrypted secrets vault for AI coding agents.