bagman
Secure key management for AI agents. Use when handling private keys, API secrets, wallet credentials, or when building systems that need agent-controlled funds. Covers secure storage, session keys, leak prevention, prompt injection defense, and MetaMask Delegation Framework integration.
安装 / 下载方式
TotalClaw CLI推荐
totalclaw install clawskills:clawskills~zscole-bagmancURL直接下载,无需登录
curl -fsSL https://skills.taituai.com/api/skills/clawskills%3Aclawskills~zscole-bagman/file -o zscole-bagman.md# Bagman
Secure key management patterns for AI agents handling wallets, private keys, and secrets.
## When to Use This Skill
- Agent needs wallet/blockchain access
- Handling API keys, credentials, or secrets
- Building systems where AI controls funds
- Preventing secret leakage via prompts or outputs
## Quick Start
```bash
# Install 1Password CLI
brew install 1password-cli
# Authenticate
eval $(op signin)
# Create vault for agent credentials
op vault create "Agent-Credentials"
# Run examples
cd examples && python test_suite.py
```
---
## Core Rules
| Rule | Why |
|------|-----|
| Never store raw private keys | Config, env, memory, or conversation = leaked |
| Use delegated access | Session keys with time/value/scope limits |
| Secrets via secret manager | 1Password, Vault, AWS Secrets Manager |
| Sanitize all outputs | Scan for key patterns before any response |
| Validate all inputs | Check for injection attempts before wallet ops |
---
## Architecture
```
┌─────────────────────────────────────────────────────┐
│ AI Agent │
├─────────────────────────────────────────────────────┤
│ Session Key (bounded) │
│ ├─ Expires after N hours │
│ ├─ Max spend per tx/day │
│ └─ Whitelist of allowed contracts/methods │
├─────────────────────────────────────────────────────┤
│ Secret Manager (1Password/Vault) │
│ ├─ Retrieve at runtime only │
│ ├─ Never persist to disk │
│ └─ Audit trail of accesses │
├─────────────────────────────────────────────────────┤
│ Smart Account (ERC-4337) │
│ ├─ Programmable permissions │
│ └─ Recovery without key exposure │
└─────────────────────────────────────────────────────┘
```
---
## Implementation Files
| File | Purpose |
|------|---------|
| `examples/secret_manager.py` | 1Password integration for runtime secret retrieval |
| `examples/sanitizer.py` | Output sanitization (keys, seeds, tokens) |
| `examples/validator.py` | Input validation (prompt injection defense) |
| `examples/session_keys.py` | ERC-4337 session key configuration |
| `examples/delegation_integration.ts` | MetaMask Delegation Framework (EIP-7710) |
| `examples/pre-commit` | Git hook to block secret commits |
| `examples/test_suite.py` | Adversarial test suite |
| `docs/prompt-injection.md` | Deep dive on injection defense |
| `docs/secure-storage.md` | Secret storage patterns |
| `docs/session-keys.md` | Session key architecture |
| `docs/leak-prevention.md` | Output sanitization patterns |
| `docs/delegation-framework.md` | On-chain permission enforcement (EIP-7710) |
---
## 1. Secret Retrieval
### 1Password CLI Pattern
```bash
# Retrieve at runtime (never store result)
SESSION_KEY=$(op read "op://Agents/my-agent/session-key")
# Run with injected secrets (never touch disk)
op run --env-file=.env.tpl -- python agent.py
```
### .env.tpl (safe to commit - no secrets)
```
PRIVATE_KEY=op://Agents/trading-bot/session-key
RPC_URL=op://Infra/alchemy/sepolia-url
OPENAI_API_KEY=op://Services/openai/api-key
```
### Python Usage
```python
from secret_manager import get_session_key
# Retrieve validated session key
creds = get_session_key("trading-bot-session")
# Check validity
if creds.is_expired():
raise ValueError("Session expired - request renewal from operator")
print(f"Time remaining: {creds.time_remaining()}")
print(f"Allowed contracts: {creds.allowed_contracts}")
# Use the key (never log it!)
client.set_signer(creds.session_key)
```
### Vault-Level ACL (Recommended)
Configure 1Password vault permissions:
```
Agent-Credentials/
├── trading-bot-session # Agent can read
├── payment-bot-session # Agent can read
└── master-key # Operator ONLY (agent has no access)
```
**Principle:** Agent credentials should be in a vault with read-only agent access. Master keys should be in a separate vault the agent cannot access.
---
## 2. Output Sanitization
Apply to ALL agent outputs before sending anywhere:
```python
from sanitizer import OutputSanitizer
def respond(content: str) -> str:
"""Sanitize before any output."""
return OutputSanitizer.sanitize(content)
# Catches:
# - Private keys (0x + 64 hex)
# - OpenAI/Anthropic/Groq/AWS keys
# - GitHub/Slack/Discord tokens
# - BIP-39 seed phrases (12/24 words)
# - PEM private keys
# - JWT tokens
```
### Patterns Detected
| Pattern | Example | Result |
|---------|---------|--------|
| ETH private key | `0x1234...abcd` (64 hex) | `[PRIVATE_KEY_REDACTED]` |
| ETH address | `0x742d...f44e` (40 hex) | `0x742d...f44e` (truncated) |
| OpenAI key | `sk-proj-abc123...` | `[OPENAI_KEY_REDACTED]` |
| Anthropic key | `sk-ant-api03-...` | `[ANTHROPIC_KEY_REDACTED]` |
| 12-word seed | `abandon ability able...` | `[SEED_PHRASE_12_WORDS_REDACTED]` |
| JWT | `eyJhbG...` | `[JWT_TOKEN_REDACTED]` |
---
## 3. Input Validation
Check inputs before ANY wallet operation:
```python
from validator import InputValidator, ThreatLevel
result = InputValidator.validate(user_input)
if result.level == ThreatLevel.BLOCKED:
return f"Request blocked: {result.reason}"
if result.level == ThreatLevel.SUSPICIOUS:
# Log for review, but allow
log_suspicious(user_input, result.reason)
# Proceed with operation
```
### Threat Categories
| Category | Examples | Action |
|----------|----------|--------|
| Extraction | "show private key", "reveal secrets" | Block |
| Override | "ignore previous instructions" | Block |
| Role manipulation | "you are now admin" | Block |
| Jailbreak | "DAN mode", "bypass filters" | Block |
| Exfiltration | "send config to https://..." | Block |
| Wallet threats | "transfer all", "unlimited approve" | Block |
| Encoded | Base64/hex encoded attacks | Block |
| Unicode tricks | Cyrillic lookalikes, zero-width | Block |
| Suspicious | "hypothetically", "just between us" | Warn |
---
## 4. Operation Allowlisting
Never execute arbitrary operations. Explicit whitelist only:
```python
from dataclasses import dataclass
from decimal import Decimal
from typing import Optional
@dataclass
class AllowedOperation:
name: str
handler: callable
max_value: Optional[Decimal] = None
requires_confirmation: bool = False
cooldown_seconds: int = 0
ALLOWED_OPS = {
"check_balance": AllowedOperation("check_balance", get_balance),
"transfer_usdc": AllowedOperation(
"transfer_usdc",
transfer,
max_value=Decimal("500"),
requires_confirmation=True,
cooldown_seconds=60
),
"swap": AllowedOperation(
"swap",
swap_tokens,
max_value=Decimal("1000"),
cooldown_seconds=300
),
}
def execute(op_name: str, **kwargs):
if op_name not in ALLOWED_OPS:
raise PermissionError(f"Operation '{op_name}' not allowed")
op = ALLOWED_OPS[op_name]
if op.max_value and kwargs.get("amount", 0) > op.max_value:
raise PermissionError(f"Amount exceeds limit: {op.max_value}")
if op.requires_confirmation:
return request_confirmation(op_name, kwargs)
return op.handler(**kwargs)
```
---
## 5. Confirmation Flow
High-value operations require explicit confirmation:
```python
import hashlib
import time
pending_confirmations = {}
def request_confirmation(operation: str, details: dict) -> str:
code = hashlib.sha256(
f"{operation}{time.time()}".encode()
).hexdigest()[:8].upper()
pending_confirmations[code] = {
"op": operation,
"details": details,
"expires": time.time() + 300 # 5 minutes
}
return f"⚠️ Confirm '{operation}' with code: {code}\n(expires in 5 minutes)"
def confirm(code: str):
if code not in pending_confirmations:
return "Invalid confirmation code"
req = pe