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
keyringlibrary 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.keywith0600permissions - 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
- Secret References are stored in the
vault_secret_refstable with akey_name,backend_key, andpolicy_label - Grants are stored in the
vault_grantstable, linking anagent_idto asecret_ref_id - When an agent calls
vault.get, the system checks for an active grant before returning the value - Grants can be revoked by setting a
revoked_attimestamp
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 deniedPrimitives
Agents interact with the vault through four primitives:
| Primitive | Description |
|---|---|
vault.set | Store a secret in the vault |
vault.get | Retrieve a secret (requires an active grant) |
vault.delete | Delete a secret from the vault |
vault.list | List 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
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
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
GET /v1/vault/secrets
curl http://localhost:3000/v1/vault/secrets \
-H "Authorization: Bearer mox_YOUR_TOKEN"Response:
{
"secrets": [
{
"id": "uuid",
"key_name": "OPENAI_API_KEY",
"policy_label": "llm",
"created_at": "2025-01-15T10:00:00Z"
}
]
}Delete a Secret
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
keyringlibrary for additional security - Vault key: 32-byte key at
~/.moxxy/vault.keywith strict0600file 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_grantstable - Grants can be revoked at any time by setting the
revoked_attimestamp - 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:
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_TOKENGrant Management
- Grant only the secrets each agent actually needs
- Revoke grants when agents no longer require access
- Audit grants periodically
Secret Rotation
- Create a new secret reference with the updated value
- Update grants to point to the new secret
- Revoke grants on the old secret
- 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- Verify the agent has a grant via
GET /v1/vault/secrets - Check that the grant has not been revoked
- Ensure the correct
agent_idandsecret_ref_idare linked
Decryption Failed
Error: Failed to decrypt secret- Verify
~/.moxxy/vault.keyexists and has correct permissions (0600) - If using
MOXXY_VAULT_KEY, verify the hex encoding is correct - The vault key may have been rotated; secrets encrypted with the old key cannot be decrypted
Vault Key Missing
Error: Vault key not found- Check that
~/.moxxy/vault.keyexists - Alternatively, set the
MOXXY_VAULT_KEYenvironment variable - If the key was lost, a new one will be generated, but existing secrets will be unrecoverable