Skip to content

Vault & Secrets

The vault is a centralized, encrypted secret management service for storing and controlling access to sensitive information like API keys, passwords, and tokens.

Architecture

┌───────────────────────────────────────────────────────────┐
│                   Centralized Vault Service                │
├───────────────────────────────────────────────────────────┤
│                                                            │
│  ┌────────────────────┐   ┌─────────────────────────┐    │
│  │   OS Keychain       │   │  SQLite (AES-GCM enc)   │    │
│  │   (keyring lib)     │   │  vault_secret_refs      │    │
│  │   macOS Keychain    │   │  vault_grants           │    │
│  │   Linux secret svc  │   │                         │    │
│  └────────────────────┘   └─────────────────────────┘    │
│                                                            │
│  Vault Key: ~/.moxxy/vault.key (32-byte, 0600 perms)     │
│                                                            │
└───────────────────────────────────────────────────────────┘
          │                         │
    ┌─────┴──────┐           ┌──────┴──────┐
    │  Agent A   │           │  Agent B    │
    │  (granted) │           │  (granted)  │
    └────────────┘           └─────────────┘

The vault is a centralized service, not per-agent storage. All secrets are managed in one place, and agents are granted explicit access to specific secrets.

Key Components

  • OS Keychain Backend: Uses the keyring library to store secrets in the operating system's native keychain (macOS Keychain on macOS, secret service on Linux)
  • AES-GCM Encryption: Secrets stored at rest in SQLite are encrypted with AES-GCM
  • Vault Key: A 32-byte key stored at ~/.moxxy/vault.key with 0600 permissions
  • MOXXY_VAULT_KEY: Optional environment variable to provide a hex-encoded key override

Grant-Based Access Control

Access to secrets is controlled through an explicit grant system. Secrets are not automatically available to agents.

How It Works

  1. Secret References are stored in the vault_secret_refs table with a key_name, backend_key, and policy_label
  2. Grants are stored in the vault_grants table, linking an agent_id to a secret_ref_id
  3. When an agent calls vault.get, the system checks for an active grant before returning the value
  4. Grants can be revoked by setting a revoked_at timestamp

Access Flow

Agent calls vault.get("API_KEY")


Check vault_grants for (agent_id, secret_ref_id)

    ├── Grant exists and not revoked → Return decrypted value

    └── No grant or revoked → Access denied

Primitives

Agents interact with the vault through four primitives:

PrimitiveDescription
vault.setStore a secret in the vault
vault.getRetrieve a secret (requires an active grant)
vault.deleteDelete a secret from the vault
vault.listList secrets the agent has access to

API Reference

All vault endpoints use the /v1/ prefix on port 3000 with Bearer token authentication (mox_ prefix).

Create a Secret Reference

bash
POST /v1/vault/secrets

curl -X POST http://localhost:3000/v1/vault/secrets \
  -H "Authorization: Bearer mox_YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "key_name": "OPENAI_API_KEY",
    "value": "sk-xxx",
    "policy_label": "llm"
  }'

Grant Agent Access

bash
POST /v1/vault/grants

curl -X POST http://localhost:3000/v1/vault/grants \
  -H "Authorization: Bearer mox_YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "agent-uuid-here",
    "secret_ref_id": "secret-ref-uuid-here"
  }'

List Secret References

bash
GET /v1/vault/secrets

curl http://localhost:3000/v1/vault/secrets \
  -H "Authorization: Bearer mox_YOUR_TOKEN"

Response:

json
{
  "secrets": [
    {
      "id": "uuid",
      "key_name": "OPENAI_API_KEY",
      "policy_label": "llm",
      "created_at": "2025-01-15T10:00:00Z"
    }
  ]
}

Delete a Secret

bash
DELETE /v1/vault/secrets/{id}

curl -X DELETE http://localhost:3000/v1/vault/secrets/{id} \
  -H "Authorization: Bearer mox_YOUR_TOKEN"

Security Model

Encryption

  • At-rest encryption: AES-GCM for all secrets stored in SQLite
  • OS keychain integration: Native OS keychain via the keyring library for additional security
  • Vault key: 32-byte key at ~/.moxxy/vault.key with strict 0600 file permissions

Secret Redaction

All SSE (Server-Sent Events) emitted by the gateway pass through a RedactionEngine that automatically scrubs secret values from output. Secrets are never exposed in event streams, logs, or agent output.

Access Control

  • Secrets are centralized, not per-agent
  • Agents must be explicitly granted access via the vault_grants table
  • Grants can be revoked at any time by setting the revoked_at timestamp
  • No cross-agent secret access without explicit grants

Key Override

Use the MOXXY_VAULT_KEY environment variable to provide a hex-encoded vault key instead of the file at ~/.moxxy/vault.key:

bash
export MOXXY_VAULT_KEY="hex-encoded-32-byte-key"

Best Practices

Naming Conventions

Use clear, consistent key names:

OPENAI_API_KEY
TELEGRAM_BOT_TOKEN
DATABASE_PASSWORD_PROD
GITHUB_TOKEN

Grant Management

  • Grant only the secrets each agent actually needs
  • Revoke grants when agents no longer require access
  • Audit grants periodically

Secret Rotation

  1. Create a new secret reference with the updated value
  2. Update grants to point to the new secret
  3. Revoke grants on the old secret
  4. Delete the old secret reference

Backup Considerations

The vault key at ~/.moxxy/vault.key is critical. If lost, encrypted secrets cannot be recovered. Back up this file securely and separately from the database.

Troubleshooting

Access Denied

Error: No active grant for secret
  1. Verify the agent has a grant via GET /v1/vault/secrets
  2. Check that the grant has not been revoked
  3. Ensure the correct agent_id and secret_ref_id are linked

Decryption Failed

Error: Failed to decrypt secret
  1. Verify ~/.moxxy/vault.key exists and has correct permissions (0600)
  2. If using MOXXY_VAULT_KEY, verify the hex encoding is correct
  3. The vault key may have been rotated; secrets encrypted with the old key cannot be decrypted

Vault Key Missing

Error: Vault key not found
  1. Check that ~/.moxxy/vault.key exists
  2. Alternatively, set the MOXXY_VAULT_KEY environment variable
  3. If the key was lost, a new one will be generated, but existing secrets will be unrecoverable

Open source · Self-hosted · Data sovereign