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:
- Compromised environment variables (leaked in logs, error messages, or CI/CD systems)
- Supply chain attacks (malicious npm/pip package reading env variables)
- Process memory dumps exposing keys at runtime
- Insecure key storage in configuration files committed to version control
- Long-running process compromise giving an attacker persistent access
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:
- Key 1: Hot key — held in the agent's encrypted keystore, used for routine operations
- Key 2: Operator key — held by the agent's owner, required to authorize large withdrawals
- Key 3: Recovery key — stored offline in cold storage, used only for emergency recovery
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
- Generate keys using a CSPRNG (Python
secretsmodule, notrandom) - Never hardcode seed phrases or private keys in source code
- Load keys exclusively from environment variables or encrypted keystores
- Redact all key material before writing to logs or error messages
- Rotate API keys and seed phrases periodically (or immediately after any suspected exposure)
- Use 2-of-3 multi-sig for wallets holding more than $10,000
- Keep the recovery key offline and physically separate from the hot and operator keys
- Never commit
.envfiles or keystores to version control - Never log the full API response if it might contain sensitive fields
- Never use test seed phrases in production (even briefly)
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