Menu
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

AssetImpact if Compromised
Private keysComplete fund loss
Seed phrasesComplete fund loss
xpubsPrivacy loss, address prediction
Transaction historyPrivacy loss
API credentialsService access, potential funds

Attack Vectors

VectorDescriptionMitigation
Memory extractionReading keys from RAMClear after use, encrypted memory
Log exposureKeys in log filesNever log sensitive data
API interceptionMan-in-the-middleTLS verification, pinned certs
Supply chainMalicious dependenciesAudit dependencies, minimal imports
Key generationWeak randomnessSystem CSPRNG only
Address reuseTransaction correlationFresh 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 RiskStorage Method
< $100Encrypted environment variable
$100 - $1,000Encrypted file, restricted permissions
$1,000 - $10,000Hardware security module (HSM)
> $10,000Multi-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

AmountRequired Signatures
< 1,000 sats1 (hot key only)
1,000 - 100,000 sats2 (hot + validation service)
> 100,000 sats2 + 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

  1. Immediately: Move funds to new wallet
  2. Assess: Determine scope of exposure
  3. Rotate: Generate new keys, update all systems
  4. Audit: Review logs for unauthorized access
  5. 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"
  }
}