Bitcoin Intermediate 15 min read
Bitcoin Security for Agents
Security best practices for AI agents handling Bitcoin. Key management, operational security, and threat modeling.
security opsec agents keys
Bitcoin Security for Agents
Security is critical for agents handling Bitcoin. Loss of keys means loss of funds—there’s no recovery mechanism, no customer support. This guide covers threat models and mitigations for autonomous agents.
Threat Model
What Agents Must Protect
| Asset | Impact if Compromised |
|---|---|
| Private keys | Complete fund loss |
| Seed phrases | Complete fund loss |
| xpubs | Privacy loss, address prediction |
| Transaction history | Privacy loss |
| API credentials | Service access, potential funds |
Attack Vectors
| Vector | Description | Mitigation |
|---|---|---|
| Memory extraction | Reading keys from RAM | Clear after use, encrypted memory |
| Log exposure | Keys in log files | Never log sensitive data |
| API interception | Man-in-the-middle | TLS verification, pinned certs |
| Supply chain | Malicious dependencies | Audit dependencies, minimal imports |
| Key generation | Weak randomness | System CSPRNG only |
| Address reuse | Transaction correlation | Fresh address per transaction |
Key Management
Generation
DO:
import secrets
import os
# Use system cryptographic randomness
private_key = secrets.token_bytes(32)
# Or from OS directly
private_key = os.urandom(32)
NEVER:
import random
# DANGEROUS: Predictable!
private_key = bytes([random.randint(0, 255) for _ in range(32)])
Storage Hierarchy
| Value at Risk | Storage Method |
|---|---|
| < $100 | Encrypted environment variable |
| $100 - $1,000 | Encrypted file, restricted permissions |
| $1,000 - $10,000 | Hardware security module (HSM) |
| > $10,000 | Multi-sig, cold storage, time-locks |
Encryption at Rest
from cryptography.fernet import Fernet
import os
# Generate encryption key (store separately!)
encryption_key = Fernet.generate_key()
# Encrypt private key
cipher = Fernet(encryption_key)
encrypted_key = cipher.encrypt(private_key)
# Store encrypted, decrypt only when needed
Memory Handling
import ctypes
def secure_wipe(data: bytes):
"""Overwrite memory before freeing"""
ptr = ctypes.cast(data, ctypes.POINTER(ctypes.c_char * len(data)))
ctypes.memset(ptr, 0, len(data))
# After use
secure_wipe(private_key_bytes)
del private_key
Operational Security
Address Management
Best Practice: One address per transaction
class AddressManager:
def __init__(self, xpub):
self.xpub = xpub
self.next_index = 0
self.used_addresses = set()
def get_fresh_address(self):
while True:
address = derive_address(self.xpub, 0, self.next_index)
self.next_index += 1
if address not in self.used_addresses:
self.used_addresses.add(address)
return address
Transaction Signing
Principle: Minimize key exposure time
def sign_transaction(psbt, encrypted_key, decryption_key):
# Decrypt key only for signing
private_key = decrypt(encrypted_key, decryption_key)
try:
signed_psbt = psbt.sign(private_key)
return signed_psbt
finally:
# Clear key immediately
secure_wipe(private_key)
del private_key
Rate Limiting
Prevent runaway transactions:
class TransactionLimiter:
def __init__(self, max_per_hour=10, max_value_per_hour=100000):
self.max_per_hour = max_per_hour
self.max_value_per_hour = max_value_per_hour # sats
self.history = []
def check_limit(self, value):
now = time.time()
hour_ago = now - 3600
# Clean old entries
self.history = [(t, v) for t, v in self.history if t > hour_ago]
# Check limits
if len(self.history) >= self.max_per_hour:
raise Exception("Transaction count limit exceeded")
total_value = sum(v for _, v in self.history)
if total_value + value > self.max_value_per_hour:
raise Exception("Transaction value limit exceeded")
self.history.append((now, value))
return True
Logging Rules
Never log:
- Private keys
- Seed phrases
- Decrypted secrets
- Full xprvs
Safe to log:
- Transaction IDs
- Public addresses
- Block heights
- Error codes (not full errors with sensitive data)
import logging
class SafeFormatter(logging.Formatter):
SENSITIVE_PATTERNS = [
r'xprv[a-zA-Z0-9]{100,}',
r'[0-9a-f]{64}', # Possible private key
r'\b[a-zA-Z]{12,24}\b' # Possible mnemonic
]
def format(self, record):
msg = super().format(record)
for pattern in self.SENSITIVE_PATTERNS:
msg = re.sub(pattern, '[REDACTED]', msg)
return msg
Multi-Signature Security
For high-value operations, require multiple signatures:
2-of-3 Setup
Key 1: Agent hot key (for convenience)
Key 2: Separate service (for validation)
Key 3: Cold storage (for recovery)
Spending Policy
| Amount | Required Signatures |
|---|---|
| < 1,000 sats | 1 (hot key only) |
| 1,000 - 100,000 sats | 2 (hot + validation service) |
| > 100,000 sats | 2 + time delay |
Implementation
from bitcoin import *
# Create 2-of-3 multisig
pubkeys = [pubkey1, pubkey2, pubkey3]
redeem_script = mk_multisig_script(pubkeys, 2, 3)
address = p2sh_scriptaddr(redeem_script)
Network Security
API Communication
import requests
import ssl
# Always verify TLS
session = requests.Session()
session.verify = True # Never disable!
# Consider certificate pinning for critical APIs
Tor for Privacy
import requests
proxies = {
'http': 'socks5h://127.0.0.1:9050',
'https': 'socks5h://127.0.0.1:9050'
}
response = requests.get(
'https://mempool.space/api/v1/prices',
proxies=proxies
)
Incident Response
If Keys Compromised
- Immediately: Move funds to new wallet
- Assess: Determine scope of exposure
- Rotate: Generate new keys, update all systems
- Audit: Review logs for unauthorized access
- Report: Document incident
Recovery Checklist
- [ ] New seed generated securely
- [ ] Old addresses monitored for movement
- [ ] All systems updated with new credentials
- [ ] API keys rotated
- [ ] Incident documented
Security Checklist
Before Deployment
- Keys generated with CSPRNG
- Keys encrypted at rest
- No keys in logs
- Rate limiting configured
- Transaction limits set
- Multi-sig for high value
- Backup tested and secured
Ongoing
- Audit logs regularly
- Monitor for unusual patterns
- Update dependencies
- Rotate API keys periodically
- Test recovery procedures
Per Transaction
- Validate recipient address
- Verify amount
- Check fee is reasonable
- Within rate limits
- Signed with minimum required keys
Machine-Readable Summary
{
"topic": "bitcoin-security",
"threat_model": ["key_theft", "memory_extraction", "api_interception", "weak_rng"],
"mitigations": {
"key_generation": "csprng_only",
"key_storage": "encrypted_at_rest",
"key_usage": "minimize_exposure_time",
"transactions": "rate_limiting",
"high_value": "multisig"
},
"security_levels": {
"low": "encrypted_env_var",
"medium": "encrypted_file_hsm",
"high": "multisig_cold_storage"
}
}