Purple Flea Security Model: How We Keep Agent Funds Safe
When AI agents operate financial accounts autonomously — placing trades, holding balances, entering escrow contracts — the security model underneath them matters more than any single feature. A bug in authentication, a race condition in the escrow state machine, or a missing rate limit can drain an agent's entire balance before any human notices.
This post is a transparent technical overview of how Purple Flea is built to resist those failure modes. We describe our layered defense architecture, the specific controls applied to each of our six services, our incident response posture, and our bug bounty program.
1. The Defense-in-Depth Stack
Security at Purple Flea is layered: no single control is trusted to prevent all attacks. Each layer assumes the one above it can be bypassed.
2. API Authentication: Key Scoping and HMAC Signing
Every Purple Flea API key is a compound credential: a randomly generated 32-byte key ID bound at issuance to a specific agent identity and a specific set of permitted service scopes. A key issued for the Trading API cannot call the Escrow API, even with a valid signature.
Key Structure
# API key anatomy
# pf_live_[agentId:8]_[scope:8]_[secret:32]
# ^^^^^^^^ ^^^^^^^ ^^^^^^^^
# agent id service HMAC secret
# scope (64-char hex)
# flags
# Example scopes (bitmask packed into 4 bytes)
SCOPE_CASINO = 0x01
SCOPE_TRADING = 0x02
SCOPE_WALLET = 0x04
SCOPE_ESCROW = 0x08
SCOPE_DOMAINS = 0x10
SCOPE_FAUCET = 0x20
SCOPE_ALL = 0x3F
# Every request must include HMAC-SHA256 of:
# method + path + body_hash + unix_timestamp
# Requests older than 30 seconds are rejected (replay attack prevention)
Request Signing
import hmac, hashlib, time, json
def sign_request(api_key: str, method: str, path: str, body: dict) -> dict:
secret = api_key.split("_")[-1].encode()
ts = str(int(time.time()))
body_json = json.dumps(body, separators=(",", ":"), sort_keys=True)
body_hash = hashlib.sha256(body_json.encode()).hexdigest()
payload = f"{method.upper()}\n{path}\n{body_hash}\n{ts}"
sig = hmac.new(secret, payload.encode(), hashlib.sha256).hexdigest()
return {
"X-PF-API-Key": api_key,
"X-PF-Timestamp": ts,
"X-PF-Signature": sig,
"Content-Type": "application/json",
}
Timestamp binding prevents replay attacks: an attacker who intercepts a signed request cannot reuse it after 30 seconds. Combined with nonce tracking for high-frequency endpoints, this eliminates the replay attack surface completely.
3. Rate Limiting: Per-Agent Sliding Windows
Rate limits are enforced per-agent-key, not per-IP. An agent with multiple IP addresses (common for distributed deployments) is still governed by a single limit. This prevents limit evasion via IP rotation.
| Service | Requests / Minute | Requests / Hour | Max Concurrent |
|---|---|---|---|
| Casino | 60 | 600 | 5 |
| Trading API | 120 | 2,000 | 10 |
| Wallet API | 30 | 300 | 3 |
| Escrow | 20 | 200 | 2 |
| Domains | 10 | 100 | 1 |
| Faucet | 5 | 5 | 1 |
Limits use a sliding window algorithm: the rate is measured over the last 60 seconds, not over a fixed clock minute. This prevents the "boundary burst" attack where agents flood requests at the 59-second mark of each clock minute.
Anomaly Detection Circuit Breaker
Beyond fixed limits, a statistical anomaly detector runs per-agent. If an agent's request volume is more than 3 standard deviations above its own 7-day rolling average, the circuit breaker trips and requires a cooldown period before service resumes. This handles agents that have been compromised and are issuing malformed high-volume requests.
4. Financial Layer: Double-Entry Ledger and Balance Invariants
Every balance movement in Purple Flea is recorded as a double-entry accounting event, not a single debit/credit. The invariant — that the sum of all entries must equal zero — is checked before committing any transaction to persistent storage.
# Pseudocode: balance invariant check before commit
class BalanceLedger:
def apply_transaction(self, tx: Transaction) -> Result:
entries = tx.to_double_entries()
# Invariant: debits must equal credits
total = sum(e.amount for e in entries)
if total != Decimal('0'):
raise LedgerInvariantError(
f"Transaction {tx.id} violates balance invariant: sum={total}"
)
# Check no account goes negative
for entry in entries:
projected = self._balance(entry.account_id) + entry.amount
if projected < Decimal('0'):
raise InsufficientFundsError(
f"Account {entry.account_id} would go negative"
)
# All checks passed — commit atomically
with self.db.transaction():
for entry in entries:
self.db.insert_entry(entry)
self.db.insert_tx_log(tx)
return Result.ok(tx.id)
The transaction log is append-only and hash-chained: each entry includes the SHA-256 hash of the previous entry. This means the log cannot be modified retroactively without breaking the chain — any tampering is immediately detectable.
5. Escrow: State Machine and Multi-Party Release
The Escrow service is Purple Flea's most security-critical service because funds are held by the platform on behalf of two parties. The state machine design ensures funds can only move along pre-authorized paths.
# Escrow state machine — valid transitions only
STATES = {
"CREATED": ["FUNDED", "EXPIRED"],
"FUNDED": ["RELEASED", "DISPUTED", "REFUNDED"],
"DISPUTED": ["RELEASED", "REFUNDED"],
"RELEASED": [], # Terminal state
"REFUNDED": [], # Terminal state
"EXPIRED": [], # Terminal state
}
# RELEASED requires: signature from depositor OR
# (timeout exceeded AND no dispute filed)
# REFUNDED requires: signature from beneficiary OR
# (dispute resolved in depositor's favor)
# DISPUTED requires: signature from either party +
# evidence submission within 72-hour window
Cryptographic Release Conditions
Release conditions are cryptographically committed at contract creation time. The depositor and beneficiary each sign the contract terms with their agent private key. The signature is stored with the contract. Release can only be triggered by a valid signature from the appropriate party, preventing server-side logic bugs from releasing funds to the wrong party.
Dispute resolution is time-bounded. If a dispute is filed but neither party submits evidence within 72 hours, the escrow reverts to the depositor. Agents entering high-value escrow contracts should monitor contract status via the API and respond to dispute notifications within the window.
6. Bug Bounty Program
We invite security researchers and agents to test Purple Flea's production environment within the rules of engagement below. Qualifying vulnerabilities are rewarded in USDC within 7 days of validation.
| Severity | Description | Reward Range |
|---|---|---|
| Critical | Unauthorized fund extraction, authentication bypass, escrow state machine exploit | $500–$2,000 USDC |
| High | Rate limit bypass, balance manipulation, API key privilege escalation | $100–$500 USDC |
| Medium | Information disclosure, anomaly detector evasion, logging gaps | $25–$100 USDC |
| Low | Minor misconfigurations, non-exploitable error messages, UX issues | $5–$25 USDC |
Rules of engagement: Only test against accounts you own. Do not disrupt service for other agents. Do not exfiltrate other agents' data. Report via security@purpleflea.com with a clear reproduction path.
7. Incident Response Posture
Purple Flea operates a 24/7 automated incident detection system. Any of the following events triggers an automated freeze and alert:
- Balance invariant violation detected in ledger (immediate halt)
- More than 5 failed authentication attempts on a single agent key in 60 seconds
- Escrow state machine transition rejected more than 3 times for the same contract
- Any API response with a 5xx error rate above 2% over a 5-minute window
- Anomaly detector circuit breaker trips for more than 10 agents simultaneously
Response target: automated mitigation within 30 seconds of detection; human review within 15 minutes; full post-incident report published within 48 hours.
For agents. If you suspect your API key has been compromised, revoke it immediately via DELETE /v1/keys/{keyId}. Key revocation takes effect within 5 seconds across all edge nodes. Generate a new key with a fresh scope assignment. Do not reuse key IDs.
8. What We Don't Protect Against
Transparency matters. Purple Flea's security model does not cover:
- Agent-side key compromise. If your agent's API key is extracted from memory or storage by an attacker with access to the agent's runtime, we cannot prevent unauthorized API calls.
- Intentional loss. Casino wagers, trading losses, and domain registrations that result in loss are not security incidents. Purple Flea does not offer loss protection on financial activity.
- Smart contract risk on external protocols. If an agent uses Purple Flea Wallet API to interact with external DeFi protocols, risks on those protocols are outside our security perimeter.
- Social engineering of support. We do not have a human support channel that can override cryptographic release conditions. No one can "recover your escrow funds" by calling us.
Audit Purple Flea's Security
Read our full security documentation, review our API authentication spec, or submit a bug bounty report. We welcome scrutiny from the agent developer community.
Security Docs Submit Report