Complete AI Agent Lockdown: 21 Policy Types for Maximum Security
Giving an AI agent a wallet without guardrails is like giving a toddler a credit card — technically functional, potentially catastrophic. If you're building AI agents that interact with crypto wallets, the security model you choose isn't an afterthought. It's the difference between a useful autonomous system and one that drains your funds on a bad inference.
This post is about exactly how WAIaaS handles that problem. Not vague promises about "enterprise-grade security" — specific mechanisms, specific policy types, and specific code you can run today.
The Actual Risk Model
Let's be honest about what can go wrong when you give an AI agent wallet access:
- The agent misinterprets a prompt and sends funds to the wrong address
- A compromised session token gets used by an attacker
- The agent executes a DeFi action with parameters outside your intended range
- Gas fees spike and the agent submits transactions at costs you'd never accept manually
- The agent approves an unlimited token allowance to a contract you didn't vet
None of these require a malicious agent. They can all happen with a well-intentioned model operating outside the boundaries you forgot to define. The solution isn't to avoid giving agents wallet access — it's to define exactly what they're allowed to do, and nothing more.
WAIaaS approaches this with three distinct security layers, a default-deny policy engine with 21 policy types across 4 security tiers, and multiple channels for human approval when transactions exceed your defined thresholds.
Layer 1: Authentication — Three Separate Keys for Three Separate Roles
The first layer is role separation. WAIaaS uses three authentication methods that map to three distinct principals:
masterAuth (Argon2id) — The system administrator role. Creates wallets, manages sessions, configures policies. This credential never touches the agent.
sessionAuth (JWT HS256) — The AI agent's credential. Scoped to a specific wallet, carries TTL and renewal limits. This is what your agent uses at runtime.
ownerAuth (SIWS/SIWE signature) — The fund owner. Used for approving transactions that exceed policy thresholds, and for kill switch recovery.
# masterAuth — system administrator (wallet creation, session management, policies)
-H "X-Master-Password: my-secret-password"
# sessionAuth — AI agent (transactions, balance queries, DeFi actions)
-H "Authorization: Bearer wai_sess_eyJhbGciOiJIUzI1NiJ9..."
# ownerAuth — fund owner (transaction approval, kill switch recovery)
-H "X-Owner-Signature: <ed25519-or-secp256k1-signature>"
-H "X-Owner-Message: <signed-message>"
Your agent only ever holds the session token. Even if that token is compromised, the attacker can only operate within the policy boundaries you've set for that session. They can't create new wallets, modify policies, or approve their own transactions. Sessions also carry per-session TTL, maximum renewal counts, and absolute lifetime limits — so a leaked token has a hard expiry.
Layer 2: The Policy Engine — Default-Deny with 21 Types
This is where the real work happens. WAIaaS implements a default-deny policy model: if you haven't explicitly allowed something, it's blocked. That means an agent with no policies configured can't transfer any tokens, can't call any contracts, and can't approve any spenders. The safe state is locked down, not open.
Policies are created by the administrator (masterAuth) and enforced by the daemon before any transaction reaches the network.
The Four Security Tiers
Every policy evaluation produces a tier assignment, and that tier determines what happens next:
INSTANT — Execute immediately, no notification
NOTIFY — Execute immediately, send notification to owner
DELAY — Queue for delay_seconds, then execute (cancellable during window)
APPROVAL — Require explicit human approval via WalletConnect, Telegram, or Push
The SPENDING_LIMIT policy maps transaction amounts to these tiers:
curl -X POST http://localhost:3100/v1/policies \
-H 'Content-Type: application/json' \
-H 'X-Master-Password: <password>' \
-d '{
"walletId": "<wallet-uuid>",
"type": "SPENDING_LIMIT",
"rules": {
"instant_max_usd": 10,
"notify_max_usd": 100,
"delay_max_usd": 1000,
"delay_seconds": 300,
"daily_limit_usd": 500,
"monthly_limit_usd": 5000
}
}'
With this configuration: transactions under $10 go through immediately. $10–$100 go through but you get notified. $100–$1,000 are queued for 5 minutes — long enough to cancel if something looks wrong. Anything over $1,000 requires your explicit approval. And nothing can exceed $500 in a day or $5,000 in a month, regardless of individual transaction amounts.
That's a meaningful security boundary defined in a single API call.
The Full List of 21 Policy Types
The SPENDING_LIMIT is the most intuitive, but the full policy set covers nearly every attack surface in crypto agent interactions:
Token and asset controls:
-
ALLOWED_TOKENS— Default-deny token whitelist. Your agent can only transfer tokens you've explicitly listed. An agent that stumbles onto a malicious token contract can't do anything with it. -
APPROVE_AMOUNT_LIMIT— Caps the maximum token approval amount. Blocks unlimited allowances, which are a common attack vector. -
APPROVED_SPENDERS— Whitelist of addresses that can receive token approvals. Your agent can't approve a random contract. -
APPROVE_TIER_OVERRIDE— Forces approval transactions into a higher security tier regardless of amount. Useful when you want human review on all approvals.
Contract and method controls:
-
CONTRACT_WHITELIST— Default-deny contract call whitelist. Your agent can only interact with contracts you've named. -
METHOD_WHITELIST— Allowed function selectors. You can permitswap()on Jupiter while blockingwithdrawAll()on the same protocol.
Network and address controls:
-
WHITELIST— Allowed recipient addresses for transfers. -
ALLOWED_NETWORKS— Restricts the agent to specific chains. An Ethereum agent has no business touching Solana, and vice versa.
Rate and time controls:
-
RATE_LIMIT— Maximum transactions per period (hourly, daily). -
TIME_RESTRICTION— Allowed hours of operation. Your trading agent doesn't need to execute at 3am.
DeFi-specific controls:
-
LENDING_LTV_LIMIT— Maximum loan-to-value ratio for lending positions. Prevents your agent from over-leveraging a lending position. -
LENDING_ASSET_WHITELIST— Allowed assets for lending protocols. -
PERP_MAX_LEVERAGE— Maximum leverage for perpetual futures positions on Hyperliquid and similar protocols. -
PERP_MAX_POSITION_USD— Maximum position size in USD. -
PERP_ALLOWED_MARKETS— Approved markets for perpetual trading. -
VENUE_WHITELIST— Allowed trading venues across protocols. -
ACTION_CATEGORY_LIMIT— Caps on DeFi action categories.
Protocol-specific controls:
-
X402_ALLOWED_DOMAINS— Whitelist for x402 HTTP payment domains. Your agent can auto-pay API calls, but only to domains you've approved. -
ERC8128_ALLOWED_DOMAINS— Allowed domains for ERC-8128 HTTP signing. -
REPUTATION_THRESHOLD— Minimum ERC-8004 onchain reputation score required for agent interactions.
This covers the range from simple spending controls all the way to DeFi-specific risk parameters. You don't have to use all 21 — but they're there when you need them.
Configuring Default-Deny Whitelists
Here's what the token whitelist looks like in practice:
curl -X POST http://localhost:3100/v1/policies \
-H 'Content-Type: application/json' \
-H 'X-Master-Password: <password>' \
-d '{
"walletId": "<wallet-uuid>",
"type": "ALLOWED_TOKENS",
"rules": {
"tokens": [
{
"address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"symbol": "USDC",
"chain": "solana"
}
]
}
}'
If your agent tries to transfer any token not on this list, the daemon returns a policy denial before the transaction is ever signed:
{
"error": {
"code": "POLICY_DENIED",
"message": "Transaction denied by SPENDING_LIMIT policy",
"domain": "POLICY",
"retryable": false
}
}
The agent gets a structured error it can handle. The transaction never leaves your node.
Layer 3: Human Approval Channels
The third layer handles the APPROVAL tier — transactions that exceed your defined thresholds and require a human decision. WAIaaS provides 3 signing channels for this: push relay, Telegram, and WalletConnect.
When a transaction hits the APPROVAL tier, it's queued. The owner receives a notification through the configured channel, reviews the transaction details, and either approves or rejects it. The daemon holds the transaction in the pipeline until that decision arrives.
# Approve a pending transaction (ownerAuth)
curl -X POST http://127.0.0.1:3100/v1/transactions/<tx-id>/approve \
-H "X-Owner-Signature: <ed25519-or-secp256k1-signature>" \
-H "X-Owner-Message: <signed-message>"
Approval requires a valid owner signature — the kind that comes from a hardware wallet or mobile signing app, not from the daemon itself. This means an attacker who compromises the daemon can queue transactions but cannot approve them.
The Transaction Pipeline
Before any transaction reaches a network, it passes through a 7-stage pipeline: validate → auth → policy → wait → execute → confirm. The policy stage is where your 21 policy types are evaluated. If any policy returns a denial, the pipeline stops there. The transaction never reaches the execute stage.
This sequential architecture means policies aren't advisory — they're enforced at the infrastructure level, not in your application code.
Simulate Before You Execute
One more safety mechanism worth knowing about: the dry-run API. Before committing any transaction, your agent can simulate it to see what would happen:
curl -X POST http://127.0.0.1:3100/v1/transactions/send \
-H "Content-Type: application/json" \
-H "Authorization: Bearer wai_sess_<token>" \
-d '{
"type": "TRANSFER",
"to": "recipient-address",
"amount": "0.1",
"dryRun": true
}'
The simulation runs the full pipeline — including policy evaluation — without broadcasting to the network. Your agent can check whether a transaction would be approved, denied, or queued before actually submitting it. This is useful for pre-flight validation in agent logic and for testing policy configurations without real funds.
Quick Start: Setting Up a Locked-Down Agent Wallet
Step 1: Start the daemon
npm install -g @waiaas/cli
waiaas init
waiaas start
Step 2: Create a wallet
curl -X POST http://127.0.0.1:3100/v1/wallets \
-H "Content-Type: application/json" \
-H "X-Master-Password: my-secret-password" \
-d '{"name": "trading-wallet", "chain": "solana", "environment": "mainnet"}'
Step 3: Set a spending limit policy
curl -X POST http://127.0.0.1:3100/v1/policies \
-H "Content-Type: application/json" \
-H "X-Master-Password: my-secret-password" \
-d '{
"walletId": "<wallet-uuid>",
"type": "SPENDING_LIMIT",
"rules": {
"instant_max_usd": 100,
"notify_max_usd": 500,
"delay_max_usd": 2000,
"delay_seconds": 900,
"daily_limit_usd": 5000
}
}'
Step 4: Create a session for your agent
curl -X POST http://127.0.0.1:3100/v1/sessions \
-H "Content-Type: application/json" \
-H "X-Master-Password: my-secret-password" \
-d '{"walletId": "<wallet-uuid>"}'
Step 5: Your agent checks balance and operates within policy
curl http://127.0.0.1:3100/v1/wallet/balance \
-H "Authorization: Bearer wai_sess_eyJhbGciOiJIUzI1NiJ9..."
From this point, the session token is the only credential your agent holds. Everything above the $100 instant threshold requires your attention. The agent operates within defined parameters, and you get notified or asked for approval on anything that exceeds them.
What's Next
The policy engine is documented interactively at http://127.0.0.1:3100/reference once your daemon is running — it's an OpenAPI 3.0 spec with a live Scalar UI where you can explore all 39 route modules and test requests directly. If you want to dig into the architecture before deploying, the codebase is fully open source and the monorepo structure (15 packages) makes it readable without needing to understand everything at once.
Start with the GitHub repo to review the security model before running anything in production: https://github.com/minhoyoo-iotrust/WAIaaS. Full documentation and the hosted version are at https://waiaas.ai.
Top comments (0)