Skip to main content

Security Model (AI-Safe Access)

secretctl follows the "Access Without Exposure" principle, ensuring AI agents can use your secrets without ever seeing them.

Core Principles

  1. AI agents never receive plaintext secrets
  2. Secrets are injected as environment variables at runtime
  3. Command output is automatically sanitized to redact leaked secrets
  4. A policy file controls which commands AI can execute

This design aligns with industry best practices for secrets management.

How It Works

┌─────────────┐     ┌──────────────────┐     ┌─────────────┐
│ AI Agent │────▶│ secretctl MCP │────▶│ Command │
│ (Claude) │ │ Server │ │ (aws, etc) │
└─────────────┘ └──────────────────┘ └─────────────┘
│ │ │
│ "Run aws s3 ls │ Inject secrets │
│ with aws/*" │ as env vars │
│ │ │
▼ ▼ ▼
Never sees Manages secrets Receives env
secret values and policy vars securely

What AI Agents Can Do

CapabilityDescription
List secretsSee key names and metadata (not values)
Check existenceVerify if a secret key exists
Get masked valuesSee last 4 characters only (****WXYZ)
Run commandsExecute allowed commands with secrets injected

What AI Agents Cannot Do

RestrictionReason
Read plaintextNo secret_get tool exists
Access blocked commandsPolicy enforcement
Bypass output sanitizationAutomatic redaction
Run arbitrary commandsAllowlist-only policy

Policy Configuration

Deny-by-Default

Always use default_action: deny in your policy:

version: 1
default_action: deny # Recommended
allowed_commands:
- aws
- gcloud
- kubectl

Commands Blocked by Default

Even with default_action: allow, these commands are always blocked:

  • env - Can leak all environment variables
  • printenv - Can leak all environment variables
  • set - Can leak shell state
  • export - Can leak all exports

Denied Commands

Explicitly deny dangerous commands:

denied_commands:
- rm
- dd
- mkfs

Output Sanitization

When a command is executed via secret_run, the output is automatically scanned for secret values. Any matches are replaced with [REDACTED:key].

Example:

If aws/secret_key contains AKIAIOSFODNN7EXAMPLE:

# Original output
Access key: AKIAIOSFODNN7EXAMPLE

# Sanitized output
Access key: [REDACTED:aws/secret_key]

Limitations

Output sanitization uses exact string matching. It does not detect:

  • Base64-encoded secrets
  • Hex-encoded secrets
  • Partial string matches

Threat Categories

secretctl's AI-Safe Access design protects against these threat categories:

1. Direct Secret Exposure

ThreatProtectionStatus
AI requests plaintext secretNo secret_get tool exists✅ Mitigated
AI extracts from command outputOutput sanitization✅ Mitigated
AI infers from partial dataFixed-length masking (****WXYZ)✅ Mitigated

2. Prompt Injection Attacks

ThreatProtectionStatus
Malicious prompt requests secretsTool-level restrictions✅ Mitigated
Injected command in secret_runCommand allowlist policy✅ Mitigated
Encoded secret extractionNot detected (see limitations)⚠️ Not Mitigated

3. Command Execution Risks

ThreatProtectionStatus
Environment variable dumpenv/printenv/set blocked✅ Mitigated
Shell escape sequencesCommand validation✅ Mitigated
Timeout/resource exhaustion300s timeout, resource limits✅ Mitigated
Arbitrary command executionDeny-by-default policy✅ Mitigated

4. Indirect Disclosure

ThreatProtectionStatus
Timing attacksNot applicable (local only)N/A
Side-channel via output lengthFixed masking format✅ Mitigated
Model training data leakageNo plaintext to AI✅ Mitigated

Sanitization Details

Sanitization uses exact string matching to replace secret values in command output.

What IS Detected

PatternExampleReplacement
Exact matchAKIAIOSFODNN7EXAMPLE[REDACTED:aws/key]
In JSON output{"key": "secret123"}{"key": "[REDACTED:api/key]"}
In URLshttps://api.example.com?token=abc123[REDACTED:api/token]

What is NOT Detected

⚠️ Known Limitations:

PatternExampleWhy Not Detected
Base64 encodingQUtJQUlPU0ZPRE5ON0VYQU1QTEU=Only exact match
Hex encoding414b494149...Only exact match
URL encoding%41%4B%49%41...Only exact match
Partial matchesFirst 10 chars of secretOnly exact match
Case variationsSECRET123 vs secret123Case-sensitive match
Split outputSEC + RET123 (across lines)Single-pass detection
Compressed datagzip/deflate encodedBinary not scanned

Sanitization Timing

Command executes → stdout/stderr captured → Sanitization runs → Result to AI

All secret values checked

Important: Sanitization happens after command completion. Secrets are exposed to the subprocess but never returned to the AI.

Best Practices

  1. Use strong master password - The MCP server requires your master password
  2. Limit allowed commands - Only allow commands you actually need
  3. Review policy regularly - Audit your allowed commands list
  4. Use key prefixes - Organize secrets with prefixes (e.g., aws/, db/)
  5. Set expirations - Use --expires when setting sensitive secrets
  6. Monitor audit logs - Check secretctl audit list for unusual activity
  7. Avoid encoding secrets - Don't store base64/hex encoded values as secrets
  8. Use short-lived tokens - Prefer tokens with expiration over long-lived credentials