DEV Community

Cover image for Complete AI Agent Lockdown: ALLOWED_TOKENS + CONTRACT_WHITELIST + METHOD_WHITELIST Triple Security
Wallet Guy
Wallet Guy

Posted on

Complete AI Agent Lockdown: ALLOWED_TOKENS + CONTRACT_WHITELIST + METHOD_WHITELIST Triple Security

Complete AI Agent Lockdown: ALLOWED_TOKENS + CONTRACT_WHITELIST + METHOD_WHITELIST Triple Security

Giving an AI agent a wallet without guardrails is like giving a toddler a credit card — technically possible, practically terrifying. If you're building autonomous agents that interact with crypto wallets, the security model you choose on day one determines whether your system survives contact with mainnet. This post walks through exactly how WAIaaS implements three interlocking default-deny policies — ALLOWED_TOKENS, CONTRACT_WHITELIST, and METHOD_WHITELIST — to create a layered lockdown that keeps your agent's autonomy useful while keeping your funds safe.

Why This Problem Is Harder Than It Looks

Most developers thinking about AI agent security jump straight to authentication. "Give the agent a key, restrict who can call the API, done." But authentication only controls who sends instructions. It says nothing about what those instructions can do.

An authenticated AI agent with a misconfigured wallet can:

  • Transfer tokens to any address it derives from context
  • Call arbitrary smart contracts passed to it through a prompt
  • Approve unlimited token spend to third-party contracts
  • Interact with protocols you've never heard of

The threat model here isn't just external attackers. It's prompt injection, model hallucination, compromised API responses, and your own agent misunderstanding ambiguous instructions. Each of these failure modes can result in fund loss even when your authentication is perfect.

This is the problem WAIaaS addresses at the policy layer, not the authentication layer. Authentication tells you the request is coming from your agent. Policy tells you whether the request is something your agent should be allowed to do.

The Default-Deny Foundation

Before diving into the three specific policies, understand the foundational principle: WAIaaS uses default-deny enforcement. Transactions are blocked unless explicitly permitted by policy.

This is the opposite of most systems, which allow everything and let you add restrictions. Default-deny means:

  • If you haven't configured ALLOWED_TOKENS, token transfers are blocked
  • If you haven't configured CONTRACT_WHITELIST, contract calls are blocked
  • If you haven't configured METHOD_WHITELIST, specific function calls can be further restricted even within whitelisted contracts

Your agent starts with zero permissions and you open up exactly what it needs. This is the correct mental model for any autonomous system touching real funds.

WAIaaS supports 21 policy types in total, but these three form the core of what you'd call "transaction lockdown." Let's go through each one.

Layer 1: ALLOWED_TOKENS

ALLOWED_TOKENS is a whitelist of tokens your agent is permitted to transfer. If a token isn't on the list, the transaction is denied before it ever reaches signing or execution.

Here's what the policy configuration looks like:

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"
        }
      ]
    }
  }'
Enter fullscreen mode Exit fullscreen mode

In this example, the agent's wallet can only transfer USDC on Solana. An instruction to send SOL, BONK, or any other token fails at the policy layer — no signing, no broadcast, no transaction fee wasted.

This matters for a specific class of attack: if an adversarial prompt convinces your agent to "send all available tokens to recover funds," ALLOWED_TOKENS means only the explicitly listed tokens are transferable. The agent literally cannot comply with instructions to move tokens outside its permitted set.

For an EVM trading agent, you might allow USDC, WETH, and a specific governance token. For a Solana payments agent, maybe just USDC and USDT. The principle is the same: enumerate exactly what the agent needs, deny everything else.

Layer 2: CONTRACT_WHITELIST

ALLOWED_TOKENS handles transfers, but most interesting DeFi activity involves contract calls — swaps, lending, staking, liquidity provision. CONTRACT_WHITELIST gives you the same default-deny treatment for smart contract interactions.

curl -X POST http://localhost:3100/v1/policies \
  -H 'Content-Type: application/json' \
  -H 'X-Master-Password: <password>' \
  -d '{
    "walletId": "<wallet-uuid>",
    "type": "CONTRACT_WHITELIST",
    "rules": {
      "contracts": [
        {
          "address": "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4",
          "name": "Jupiter",
          "chain": "solana"
        }
      ]
    }
  }'
Enter fullscreen mode Exit fullscreen mode

With this policy active, your agent can interact with Jupiter's contract but nothing else. An agent running an on-chain strategy has no path to accidentally — or maliciously via prompt injection — call an unknown contract address, a newly deployed protocol, or a phishing contract disguised as a legitimate one.

This is particularly important when your agent is consuming external data to determine where to execute trades. If the agent is reading prices from an API, a compromised API response could theoretically return a malicious contract address as the "best venue." CONTRACT_WHITELIST means the agent will attempt the call, the policy engine will check the target address, find it's not on the whitelist, and return a POLICY_DENIED error — never reaching the blockchain.

The error response looks like this:

{
  "error": {
    "code": "POLICY_DENIED",
    "message": "Transaction denied by CONTRACT_WHITELIST policy",
    "domain": "POLICY",
    "retryable": false
  }
}
Enter fullscreen mode Exit fullscreen mode

Your agent gets a clear, structured error it can log and handle. No ambiguity, no silent failure.

Layer 3: METHOD_WHITELIST

The third layer operates at a finer granularity than CONTRACT_WHITELIST. Where CONTRACT_WHITELIST controls which contracts can be called, METHOD_WHITELIST controls which functions within those contracts can be called.

Consider a scenario: you've whitelisted a lending protocol contract. That contract exposes functions for depositing collateral, borrowing, repaying, and withdrawing. Maybe your agent's job is to manage collateral — deposit and withdraw — but you never want it to borrow autonomously. METHOD_WHITELIST lets you express exactly that constraint by specifying allowed function selectors.

This is the difference between "my agent can touch this contract" and "my agent can touch this contract, but only call these specific functions." For risk management, that distinction is significant. An agent that can deposit into Aave is very different from an agent that can also borrow from Aave.

When combined with CONTRACT_WHITELIST, the combination means:

  1. The target contract must be on the whitelist
  2. And the function being called must be on the method whitelist

Both conditions must be satisfied. Neither alone is sufficient.

How These Three Layers Stack

The power of this approach is multiplicative, not additive. Each policy operates as an independent gate in the transaction pipeline. WAIaaS processes transactions through a 7-stage pipeline: validation, auth, policy, wait, execute, confirm. Policy evaluation happens at stage 3, before any signing or execution occurs.

For a transaction to succeed, it must pass every applicable policy:

  • Is the token in ALLOWED_TOKENS? → If no, denied.
  • Is the contract in CONTRACT_WHITELIST? → If no, denied.
  • Is the method in METHOD_WHITELIST? → If no, denied.

You can visualize this as concentric rings of restriction. ALLOWED_TOKENS is the outermost ring (what assets can move). CONTRACT_WHITELIST is the middle ring (where can those assets go). METHOD_WHITELIST is the innermost ring (what can be done once there).

An agent trying to do something outside any of these rings hits a wall immediately.

Combining with Spending Limits and Approval Tiers

Token and contract whitelists tell you what is allowed. Spending limits tell you how much is allowed, and in what manner. These policies compose.

Here's a realistic production setup that combines a spending limit with token restrictions:

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
    }
  }'
Enter fullscreen mode Exit fullscreen mode

WAIaaS uses 4 security tiers:

  • INSTANT — Execute immediately, no notification
  • NOTIFY — Execute immediately, send notification to owner
  • DELAY — Queue for the specified delay period, cancellable before execution
  • APPROVAL — Require explicit human approval before executing

Tier assignment is automatic based on transaction amount. In the example above: transactions under $100 execute instantly, $100-$500 execute with notification, $500-$2,000 queue for 15 minutes, and anything over $2,000 requires human approval.

Combined with CONTRACT_WHITELIST and ALLOWED_TOKENS, this means: even for transactions that pass the token and contract checks, large amounts automatically escalate to human review. Your agent can be fully autonomous for small, routine operations and automatically require oversight for anything unusual.

The Dry-Run Safety Net

Before pushing any of this to production, you can validate your transaction logic — including policy evaluation — using the dry-run API. This simulates the full transaction pipeline without submitting anything to the blockchain:

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
  }'
Enter fullscreen mode Exit fullscreen mode

The response tells you whether the transaction would succeed or fail, and if it would fail, which policy blocked it. This is invaluable when setting up policies: you can iterate on your configuration and verify the behavior without risking funds or gas.

Use dry-run during development to confirm that:

  • Transactions your agent should execute pass all policies
  • Transactions your agent should be blocked from attempting are correctly denied
  • The tiers assigned to different amounts match your expectations

Setting Up: The Minimal Secure Configuration

Here's a minimal sequence to get a locked-down agent wallet running. This assumes you already have WAIaaS running via Docker or CLI.

Step 1: Create the 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"}'
Enter fullscreen mode Exit fullscreen mode

Step 2: Create a session token 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>"}'
Enter fullscreen mode Exit fullscreen mode

Step 3: Apply your three lockdown policies (ALLOWED_TOKENS, CONTRACT_WHITELIST, METHOD_WHITELIST — using the examples above)

Step 4: Apply a spending limit with approval tier for large transactions (SPENDING_LIMIT — using the example above)

Step 5: Verify with a dry-run before giving the session token to your agent

Your agent receives the session token and can now make calls to the wallet API. Everything it tries will be evaluated against the policy stack before any signing occurs. The agent's code doesn't need to know about policies — it just makes API calls, and the policy engine handles enforcement transparently.

Authentication: Three Roles, Separated Concerns

The policy layer works in conjunction with WAIaaS's three-role authentication model:

# 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>"
Enter fullscreen mode Exit fullscreen mode

Your agent only ever holds a sessionAuth token. It cannot create wallets, modify policies, or approve its own transactions. Policy changes require masterAuth. Transaction approvals — when the APPROVAL tier triggers — require ownerAuth, which is a cryptographic signature from the wallet owner's key.

This means an attacker who compromises your agent's session token has a token that:

  • Can only operate on the specific wallet it was issued for
  • Is constrained by whatever policies you've applied
  • Cannot modify those policies
  • Cannot self-approve transactions that require human sign-off

The separation of concerns between these three auth levels is a meaningful security property, not a cosmetic one.

What's Next

The policies covered here — ALLOWED_TOKENS, CONTRACT_WHITELIST, and METHOD_WHITELIST — are the foundation of transaction lockdown, but WAIaaS includes 18 additional policy types covering DeFi-specific constraints (LENDING_LTV_LIMIT, PERP_MAX_LEVERAGE, PERP_MAX_POSITION_USD), network restrictions (ALLOWED_NETWORKS), approval workflow configuration (APPROVE_AMOUNT_LIMIT, APPROVE_TIER_OVERRIDE), and more. Start with the three layers here, verify your configuration with dry-runs, and then layer additional policies as your agent's responsibilities expand.

Explore the full codebase and policy documentation at https://github.com/waiaas/WAIaaS, and find deployment guides, SDK references, and the interactive API explorer at https://waiaas.ai.

Top comments (0)