9 min read

Securing AI Agent Wallets: Seed Phrases, Key Management, and Best Practices

Crypto private keys have one immutable property: if they are lost or stolen, there is no recovery path. No customer support ticket, no password reset, no insurance claim. For AI agents holding real funds, wallet security is not optional — it is the foundation that everything else is built on.

Why Agent Wallet Security Is Different

Human wallet security is hard. Agent wallet security is harder. Agents run continuously, often unattended, and interact with many external services. They also typically store credentials in configuration files, environment variables, or databases — all of which are attack surfaces that a human wallet owner would never encounter.

The threat model for an AI agent wallet includes:

No Recovery Exists

A compromised or lost private key means total and permanent loss of any funds held at that address. There is no exception to this rule in any major cryptocurrency. Design your key management accordingly.

Purple Flea Handles Custody — Here Is What That Means

When an agent registers on Purple Flea and uses the multi-chain wallet API, Purple Flea holds the private keys server-side. Your agent authenticates with an API key and never sees the raw seed phrase or private key for its Purple Flea wallet. This is the custodial model — simpler for agents, and Purple Flea's security infrastructure protects the keys.

This means your agent's primary security concern for Purple Flea funds is protecting its PURPLEFLEA_API_KEY — not a seed phrase. Rotate this key immediately if you suspect compromise.

However, many agents also maintain external wallets — Bitcoin nodes, Monero wallets, on-chain DeFi signers — where they do control raw private keys. For these, the following practices apply.

BIP-39 Seed Phrase Generation

If your agent generates its own wallet, always use BIP-39 compliant 24-word seed phrases (256 bits of entropy). Never use 12-word phrases for high-value wallets. The additional 128 bits of entropy matters at scale.

# Install: pip install mnemonic
from mnemonic import Mnemonic
import secrets

def generate_secure_seed():
    # Use system CSPRNG — never use random.random() for key generation
    mnemo = Mnemonic("english")
    entropy = secrets.token_bytes(32)  # 256 bits
    words = mnemo.to_mnemonic(entropy)
    return words  # 24-word phrase

# NEVER do this:
# seed = "abandon abandon abandon..."  # hardcoded — catastrophic
# seed = os.environ.get("SEED", "abandon abandon abandon...")  # default is a trap

Secure Key Loading from Environment Variables

The minimum viable secure pattern for agent key storage is environment variables loaded at process start — never hardcoded, never written to disk in plaintext, never logged.

import os
import sys

def load_keys_from_env():
    # Fail loudly if any required key is missing — never use defaults
    required = [
        "PURPLEFLEA_API_KEY",
        "BTC_WALLET_SEED",       # optional: only if using self-custodied BTC
    ]
    keys = {}
    missing = []
    for key in required:
        val = os.environ.get(key)
        if not val:
            missing.append(key)
        else:
            keys[key] = val

    if missing:
        print(f"ERROR: Missing required env vars: {', '.join(missing)}", file=sys.stderr)
        # Do NOT print which keys are present — that leaks partial information
        sys.exit(1)

    return keys

def sanitize_logs(message: str, keys: dict) -> str:
    # Redact any key material before logging
    for val in keys.values():
        if val and len(val) > 8:
            message = message.replace(val, "[REDACTED]")
    return message

Encrypted Key Storage for Persistent Agents

For agents that need to persist keys across restarts without relying solely on env vars, use encrypted key storage with a key-encryption-key (KEK) derived from a passphrase stored separately.

# Install: pip install cryptography
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives import hashes
import base64, os, json

def derive_key(passphrase: str, salt: bytes) -> bytes:
    kdf = PBKDF2HMAC(
        algorithm=hashes.SHA256(),
        length=32,
        salt=salt,
        iterations=480000  # OWASP 2026 recommendation
    )
    return base64.urlsafe_b64encode(kdf.derive(passphrase.encode()))

def encrypt_keystore(seeds: dict, passphrase: str, path: str):
    salt = os.urandom(16)
    key = derive_key(passphrase, salt)
    f = Fernet(key)
    ciphertext = f.encrypt(json.dumps(seeds).encode())
    with open(path, "wb") as fp:
        fp.write(salt + ciphertext)
    os.chmod(path, 0o600)  # owner read-write only

def decrypt_keystore(passphrase: str, path: str) -> dict:
    with open(path, "rb") as fp:
        data = fp.read()
    salt, ciphertext = data[:16], data[16:]
    key = derive_key(passphrase, salt)
    f = Fernet(key)
    return json.loads(f.decrypt(ciphertext))

# Key rotation: generate new seed, re-encrypt, update on-chain if needed
def rotate_key(old_pass: str, new_pass: str, path: str):
    seeds = decrypt_keystore(old_pass, path)
    # Optionally generate new seeds here and transfer funds
    encrypt_keystore(seeds, new_pass, path)
    print("Key rotation complete.")

Multi-Signature for High-Value Agent Wallets

For agents holding significant funds (above $10,000 equivalent), consider a 2-of-3 multi-sig setup. This means any transaction requires signatures from 2 out of 3 keys. Even if one key is compromised, an attacker cannot drain funds.

A practical 2-of-3 split for an autonomous agent:

This setup lets the agent operate autonomously for small transactions while requiring human sign-off for large moves — a natural circuit breaker against both bugs and compromise.

Best Practices Checklist

Emergency Recovery Plan

If your agent process crashes mid-transaction, two scenarios require immediate attention:

Transaction broadcast but not confirmed: The transaction is in the mempool. Query the blockchain explorer with the transaction hash. If it is stuck (insufficient fees), use Replace-By-Fee (RBF) on Bitcoin or speed up on EVM chains. The funds are safe — they just need the transaction to confirm.

Transaction signed but not broadcast: The signed bytes are likely lost. You will need to reconstruct and re-sign the transaction. Always log the transaction hash (not the raw signed bytes) before broadcasting, so you can determine state on restart.

For Purple Flea API calls, all transactions are idempotent with request IDs — if a call fails mid-flight, you can safely retry with the same request ID without double-spending.

Start with Custody-Free Agent Wallets

Purple Flea manages key custody server-side. Your agent authenticates with an API key — never handles raw seed phrases for on-platform funds.

Explore Wallet API Multi-Sig Guide