Maximus · Security

Credential Vault

AES-256-GCM encrypted secret storage with a proxy pattern that keeps credentials out of agent context entirely. Agents never see secrets — the infrastructure resolves, injects, and sanitizes on their behalf.

Overview Architecture

The credential vault stores secrets encrypted at rest using AES-256-GCM. Agents never have access to credentials directly. The vault key lives in the tool executor process. When a tool needs credentials, the infrastructure resolves them from the vault and injects them into the API call.

This architecture ensures that even if an agent's context is leaked or logged, no secrets are exposed. The entire credential lifecycle — decryption, injection, and cleanup — happens in a layer the agent cannot observe.

How It Works Proxy Pattern

The credential vault uses a proxy pattern to keep secrets out of agent context. The agent only sees business parameters in and a sanitized result out. At no point does the agent have access to any token, API key, or credential. The entire credential lifecycle happens in the tool executor layer.

Agent
  -> tool("create_issue", { repo, title })
    -> Tool Executor
      -> Vault.resolve("github_token")
        -> HTTP call with token
          -> sanitized result
            -> Agent

Setup Configuration

Environment Variable

Set MAXIMUS_VAULT_KEY as an environment variable. This is the master key used to derive the encryption key (via scrypt) for encrypting and decrypting credentials.

# Linux/macOS
export MAXIMUS_VAULT_KEY="your-secure-vault-key-here"

# Or in a .env file (never commit to git)
MAXIMUS_VAULT_KEY=your-secure-vault-key-here

Storage Recommendations

Local Dev
.env file (add to .gitignore) or export in shell profile
Production
systemd environment, Docker secrets, or a secrets manager
CI / CD
Environment variable in your CI platform's secrets store

Interactive Fallback

For local development, if MAXIMUS_VAULT_KEY is not set and the process is running in an interactive terminal (TTY), the engine will prompt for the vault key. This fallback is disabled in non-interactive environments (CI, background processes) where stdin.isTTY is false.

Enter vault key (MAXIMUS_VAULT_KEY): _

Adding Credentials API

Create & Populate a Vault

Use the CredentialVault API to add credentials programmatically:

import { CredentialVault } from "@maximus/vault";

// Create or open a vault
const vault = new CredentialVault(process.env.MAXIMUS_VAULT_KEY!);

// Add credentials
vault.set("github_token", "ghp_your_token_here", {
  description: "GitHub PAT with repo scope",
});

vault.set("slack_webhook", "https://hooks.slack.com/services/T00/B00/xxx", {
  description: "Slack webhook for #engineering channel",
});

// Save encrypted vault to disk
vault.save("config/credentials.enc");

Load & Manage

Load an existing vault, list stored credentials (metadata only), check existence, or remove entries:

const vault = CredentialVault.load("config/credentials.enc", process.env.MAXIMUS_VAULT_KEY!);

// List stored credentials (metadata only, no values)
const creds = vault.list();
// [{ name: "github_token", description: "...", createdAt: "...", updatedAt: "..." }]

// Check if a credential exists
vault.has("github_token"); // true

// Remove a credential
vault.delete("github_token");

Referencing in Skills YAML

Skills reference credentials by name. The ref must match the name used in vault.set(). At tool execution time, template variables are replaced with decrypted values from the vault. The agent never sees the actual token value.

# In a skill YAML file
credentials:
  - ref: github_token
    inject_as: GITHUB_TOKEN

tools:
  - name: github_create_issue
    credentials:
      - ref: github_token
        inject_as: GITHUB_TOKEN
    action:
      type: http
      method: POST
      url: "https://api.github.com/repos/{{repo}}/issues"
      headers:
        Authorization: "Bearer {{GITHUB_TOKEN}}"

Output Sanitization PostToolUse

Tool output is automatically sanitized to strip leaked secrets before being returned to the agent. The sanitizer runs as a PostToolUse hook on every SDK session. Patterns are ordered from specific to generic to minimize false positives.

Pattern Replacement Example
Anthropic API keys sk-ant-... [REDACTED_ANTHROPIC_KEY] sk-ant-abc123...
OpenAI API keys sk-... [REDACTED_API_KEY] sk-proj-abc123...
GitHub tokens ghp_ gho_ ghu_ ghs_ ghr_ [REDACTED_GH_TOKEN] ghp_abc123...
AWS access keys AKIA... [REDACTED_AWS_KEY] AKIAIOSFODNN7EXAMPLE
Bearer / token / key assignments [REDACTED] Bearer eyJ...
Connection strings [REDACTED_CONN_STRING] postgres://user:pass@host/db
Authorization headers Authorization: [REDACTED] Authorization: Basic abc...
Long hex strings (40+ chars) [REDACTED_HASH] SHA hashes, hex-encoded tokens

Security Model Defense in Depth

The credential vault implements a three-layer defense ensuring credentials remain secure throughout the entire agent lifecycle: at rest, during execution, and in output.

Layer 1 — Encryption at Rest

AES-256-GCM

Credentials are encrypted using AES-256-GCM with a key derived from the vault key via scrypt (with a random salt). Each credential gets its own random initialization vector (IV), preventing identical plaintext from producing identical ciphertext.

Key Derivation
scrypt with random salt — computationally expensive to brute-force
Tamper Detection
GCM authentication tag ensures any modification to the ciphertext is detected on decryption
IV Strategy
Random IV per credential — identical secrets produce different ciphertext
Cipher
AES-256-GCM — authenticated encryption with associated data (AEAD)
Layer 2 — Proxy Pattern (Runtime Isolation)

RUNTIME

Credentials are never present in the agent's context. The CredentialProxy resolves credentials from the vault only at tool execution time, in the tool executor process. The vault key itself is blocked from the SDK subprocess environment.

filterEnvForSdk

Strips sensitive environment variables before spawning agent processes. Blocked keys include: MAXIMUS_VAULT_KEY, VAULT_KEY, ENCRYPTION_KEY, and MASTER_KEY.

Credential Resolution
Happens only in the tool executor process at the moment of tool invocation
Agent Visibility
Agent sees business parameters in, sanitized result out — never the raw credential
Environment Isolation
filterEnvForSdk strips vault keys from subprocess env before spawning
Scope
Credentials scoped per-skill — tools can only access credentials declared in their skill definition
Layer 3 — Output Sanitization

POSTTOOLUSE

Even if a credential somehow appears in a tool's output (e.g., an error message containing a token), the PostToolUse sanitizer hook catches and redacts it before the output reaches the agent. The regex pipeline processes patterns from most-specific to most-generic to minimize false positives.

Hook Type
PostToolUse — runs on every SDK session after every tool call
Pattern Matching
Regex pipeline ordered specific-to-generic for minimal false positives
Coverage
API keys, tokens, connection strings, auth headers, hex hashes — 8 pattern categories
Fail-Safe
Last line of defense — catches secrets that bypass proxy pattern (e.g., error stack traces)

Together, these three layers ensure that credentials remain secure throughout the entire agent lifecycle: at rest (encrypted on disk), during execution (proxy pattern isolates the agent), and in output (sanitizer catches any leaks before they reach the context window).

Maximus — Self-hosted agent orchestration · Docs Home