4-Tier Security for AI Agents: INSTANT to APPROVAL Transaction Controls

4-Tier Security for AI Agents: INSTANT to APPROVAL Transaction Controls

Giving an AI agent a wallet without guardrails is like giving a toddler a credit card — the agent will happily spend whatever it can reach, as fast as it can reach it. Security-minded developers building crypto applications with autonomous agents need a concrete answer to a concrete question: exactly what stands between your AI agent and your funds? This post breaks down WAIaaS's layered approach to that problem, from default-deny policies to human approval channels, with the specific mechanisms you can verify in the codebase yourself.

The Stakes Are Real

An AI agent that executes transactions autonomously is useful precisely because it doesn't stop to ask permission every time. That same property makes it dangerous. A compromised session token, a hallucinated recipient address, a rogue prompt injection, a runaway trading loop — any of these can drain a wallet in seconds if nothing stops them. The security model for AI agent wallets has to be designed for adversarial conditions, not just happy-path usage. Vague promises about "enterprise-grade security" don't help you. Specific mechanisms that you can configure, audit, and test do.

WAIaaS is an open-source, self-hosted Wallet-as-a-Service built specifically for AI agents. "Self-hosted" matters here: your keys and your policy engine run on your infrastructure, not on a third-party server you have to trust blindly. The entire security architecture is in the code, verifiable, and configurable.

Layer 1: Three Authentication Tiers, Strictly Separated

Before a transaction even reaches the policy engine, it has to pass through the right authentication gate. WAIaaS uses three distinct auth methods with non-overlapping privileges:

# 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>"

The separation is intentional and hard. The AI agent only ever holds a session token (wai_sess_...). It cannot create wallets, modify policies, or approve its own transactions — those operations require masterAuth (Argon2id-hashed master password) or ownerAuth (cryptographic signature from the owner's key via SIWE/SIWS). A compromised session token gives an attacker access only to what the session was explicitly configured to do, bounded by the policies you set.

Sessions themselves have configurable TTL, max renewals, and absolute lifetime. An agent session can be scoped to expire after a short window, limiting the blast radius of a stolen token.

Layer 2: Default-Deny Policies

This is the part that matters most. The WAIaaS policy engine is default-deny: your agent cannot touch tokens you haven't explicitly allowed. It cannot call contracts you haven't whitelisted. It cannot send to recipient addresses outside your approved list. If you haven't configured permission, the answer is no.

There are 21 policy types organized around a four-tier security model:

INSTANT   — Execute immediately, no notification
NOTIFY    — Execute immediately, send notification to owner
DELAY     — Queue for delay_seconds, then execute (cancellable window)
APPROVAL  — Require human approval via WalletConnect/Telegram/Push

Every transaction gets classified into one of these tiers based on your policy rules. Here's a concrete SPENDING_LIMIT policy that demonstrates all four tiers in action:

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
    }
  }'

With this policy: a $50 transaction executes immediately; a $300 transaction executes immediately but you get notified; a $1,000 transaction queues for 15 minutes (900 seconds) during which you can cancel it; anything over $2,000 requires your explicit approval. You didn't have to write this logic — you configured it once.

The tier assignment formula is unambiguous: amount <= instant_max → INSTANT, <= notify_max → NOTIFY, <= delay_max → DELAY, > delay_max → APPROVAL. No fuzzy logic, no AI judgment calls on the security path.

Layer 3: Human Approval Channels

For transactions that reach the APPROVAL tier, someone has to approve them. WAIaaS provides three signing channels for delivering that approval request to the fund owner: a push relay channel, a Telegram channel, and a WalletConnect channel. The owner signs the approval with their private key (ownerAuth), which means approval cannot be forged by anything that only has access to the session token.

# Owner approves a pending transaction
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>"

The DELAY tier also gives you a cancellable window without requiring explicit approval — useful for medium-risk transactions where you want the opportunity to intervene, but don't want to be woken up at 3am for routine operations.

The Full Set of 21 Policy Types

Spending limits are the most intuitive policy, but WAIaaS's policy engine covers the full surface area of what an agent can do. Here's the complete list:

SPENDING_LIMIT          — Amount-based 4-tier security
WHITELIST               — Allowed recipient addresses
TIME_RESTRICTION        — Allowed transaction hours
RATE_LIMIT              — Max transactions per period
ALLOWED_TOKENS          — Token transfer whitelist (default-deny)
CONTRACT_WHITELIST      — Contract call whitelist (default-deny)
METHOD_WHITELIST        — Allowed function selectors
APPROVED_SPENDERS       — Token approval whitelist (default-deny)
APPROVE_AMOUNT_LIMIT    — Max approve amount, block unlimited approvals
APPROVE_TIER_OVERRIDE   — Force tier for APPROVE transactions
ALLOWED_NETWORKS        — Network restriction
X402_ALLOWED_DOMAINS    — x402 payment domain whitelist
LENDING_LTV_LIMIT       — Max loan-to-value ratio for DeFi lending
LENDING_ASSET_WHITELIST — Allowed lending assets
PERP_MAX_LEVERAGE       — Max perpetual futures leverage
PERP_MAX_POSITION_USD   — Max position size in USD
PERP_ALLOWED_MARKETS    — Allowed perpetual markets
REPUTATION_THRESHOLD    — ERC-8004 onchain reputation threshold
ERC8128_ALLOWED_DOMAINS — ERC-8128 HTTP signing domains
VENUE_WHITELIST         — Allowed trading venues
ACTION_CATEGORY_LIMIT   — DeFi action category limits

A few of these deserve special attention for security-minded developers:

ALLOWED_TOKENS is default-deny: if you don't explicitly list a token, the agent cannot transfer it. This prevents an agent from moving tokens you didn't anticipate it ever touching.

CONTRACT_WHITELIST is also default-deny: the agent cannot call a smart contract unless you've whitelisted that contract address. Combined with METHOD_WHITELIST (allowed function selectors), you can lock an agent down to exactly the contracts and functions it legitimately needs.

APPROVE_AMOUNT_LIMIT blocks unlimited token approvals — a common attack vector where a compromised agent sets a MAX_UINT256 approval for a malicious contract. You can enforce that all approvals are bounded.

PERP_MAX_LEVERAGE and PERP_MAX_POSITION_USD are purpose-built for agents trading perpetual futures. A runaway agent can't take on 100x leverage or open a position larger than your configured maximum.

TIME_RESTRICTION lets you lock the agent to business hours. An agent that only operates 9–17 UTC has a much smaller window for damage if compromised overnight.

Simulate Before You Execute

WAIaaS includes a dry-run mode for simulating transactions before they hit the network. This lets you verify that a transaction will pass policy checks and behave as expected without actually committing funds:

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
  }'

Use this during development to validate that your policy configuration catches what you intend it to catch before you deploy to production. It's also useful for testing that a new policy doesn't inadvertently block legitimate agent operations.

The 7-Stage Transaction Pipeline

Every transaction passes through a seven-stage pipeline: validation, authentication, policy check, wait (for DELAY/APPROVAL tiers), execution, and confirmation. The policy stage isn't bolted on as an afterthought — it's stage three, before any execution happens. A transaction that fails policy never reaches the execution stage.

When a policy blocks a transaction, the error response tells you exactly why:

{
  "error": {
    "code": "POLICY_DENIED",
    "message": "Transaction denied by SPENDING_LIMIT policy",
    "domain": "POLICY",
    "retryable": false
  }
}

This is important for debugging agent behavior: you can see precisely which policy fired and why, rather than getting a generic rejection.

Gas Conditional Execution

One additional safety mechanism worth mentioning: WAIaaS supports gas conditional execution, where transactions only execute when the gas price meets a configured threshold. This prevents an agent from executing transactions during gas price spikes — useful both for cost control and for avoiding scenarios where high-fee environments cause unexpected behavior.

Quick Start: Setting Up Policies in 5 Steps

Here's the minimal path to getting a security-configured agent wallet running:

Step 1: Install and start WAIaaS

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: Configure your 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": 10,
      "notify_max_usd": 100,
      "delay_max_usd": 500,
      "delay_seconds": 300,
      "daily_limit_usd": 1000
    }
  }'

Step 4: Add an allowed token policy (default-deny)

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": "ALLOWED_TOKENS",
    "rules": {
      "tokens": [{"address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "symbol": "USDC", "chain": "solana"}]
    }
  }'

Step 5: Create a session token for your agent and test with dry-run

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>"}'

Use the returned session token in your agent, and run a dryRun: true transaction first to verify the policy configuration catches what you expect.

What's Next

The WAIaaS policy engine documentation and Admin Web UI (available at /admin) let you manage all 21 policy types visually and inspect the real-time state of pending and delayed transactions. For production deployments, the Docker Secrets overlay (docker-compose.secrets.yml) keeps your master password out of environment variables entirely.

If you're building a security-critical application, the codebase is open and the security mechanisms are verifiable — not claims in a marketing doc. Start with the GitHub repository and read the pipeline stages and policy schemas directly:

The goal isn't to make AI agents trustworthy by magic — it's to build specific, auditable guardrails so that when something goes wrong, the blast radius is bounded and you're in control.