Security marketing is full of buzzwords. At PolicyLayer, we believe in "Provable Security."
Our core architecture is based on a concept called Two-Gate Enforcement. This post explains the cryptography behind how we secure agent transactions without ever holding your private keys.
The Challenge
We need to validate a transaction against a policy (e.g., "Max $100") before it is broadcast to the blockchain, but we (PolicyLayer) do not have the private key to sign it.
This creates a timing gap: the moment between "policy approved this transaction" and "transaction actually signed." In that gap, a compromised agent could modify the transaction—changing the amount, recipient, or asset—and still claim it was approved.
The question: How do we cryptographically bind a policy decision to the exact transaction that gets signed?
Why Two Gates? The Single-Gate Vulnerability
Many policy systems use a single checkpoint: validate the intent, return approval, done. This seems sufficient, but it's fundamentally broken.
Single-gate flow:
Agent → Policy Check → "Approved" → Agent signs whatever it wants
The problem: there's no verification that what gets signed matches what was approved. The "Approved" response is just a boolean. A malicious or buggy agent can:
- Request approval for a $50 transfer
- Receive "Approved"
- Sign a $50,000 transfer instead
- Broadcast to blockchain
The policy system has no way to detect this substitution. It approved something, but has no cryptographic proof of what.
The Two-Gate Solution
Two-gate enforcement closes this gap by creating a cryptographic link between approval and execution.
┌─────────┐ ┌──────────────┐ ┌──────────────┐ ┌─────────┐
│ Agent │──────▶│ Gate 1: │──────▶│ Gate 2: │──────▶│ Sign & │
│ │ Intent│ Validate │ Token │ Verify │Approve│Broadcast│
└─────────┘ │ + Hash │ │ Hash Match │ └─────────┘
└──────────────┘ └──────────────┘
Gate 1 doesn't just say "approved"—it creates a fingerprint of the exact transaction and embeds it in a signed token.
Gate 2 re-calculates the fingerprint and compares. If anything changed, the hashes won't match.
Gate 1: Intent Validation
-
The Agent constructs a transaction object (the Intent):
To: 0xBobValue: 50 USDCChain: Base
The SDK sends this Intent to the PolicyLayer API.
-
The API evaluates against policies:
- Does this violate the Daily Limit? No.
- Is 0xBob whitelisted? Yes.
- Is 50 USDC under the per-transaction limit? Yes.
The API creates a fingerprint of the Intent:
function calculateFingerprint(intent: TransactionIntent): string {
const canonical = JSON.stringify({
chain: intent.chain,
asset: intent.asset,
to: intent.to.toLowerCase(),
amount: intent.amount,
// Include all fields that affect the transaction
});
return crypto.createHash('sha256').update(canonical).digest('hex');
}
-
The API issues a signed JWT containing:
- The fingerprint hash
- Timestamp and expiry (60 seconds)
- Unique token ID (for replay prevention)
Gate 2: Verification & Signing
The Agent receives the Auth Token.
Before signing, the SDK calls Gate 2 with the Intent + Auth Token.
-
The Validator performs three checks:
- Is the JWT signature valid? (Proves it came from PolicyLayer)
- Has the token expired? (60-second window)
- Has the token been used before? (Replay prevention)
The Critical Check: Re-calculate the fingerprint from the current Intent:
If (CurrentHash === AuthToken.Hash) → APPROVE
If (CurrentHash !== AuthToken.Hash) → REJECT: "Intent modified"
Mark token as consumed (single-use enforcement).
Only then does the agent sign and broadcast.
Attack Scenarios: What Two-Gate Prevents
Tampering Attack (Primary Threat)
Without Gate 2:
- Agent requests approval for 50 USDC to 0xBob
- Receives approval
- Modifies to 50,000 USDC to 0xAttacker
- Signs and broadcasts
- Policy system has no idea
With Gate 2:
- Agent requests approval for 50 USDC to 0xBob
- Receives token with fingerprint
abc123... - Modifies to 50,000 USDC to 0xAttacker
- Calls Gate 2: fingerprint is now
xyz789... -
xyz789 !== abc123→ REJECTED
Replay Attack
Without single-use tokens:
- Agent gets approval for legitimate 50 USDC transfer
- Saves the approval token
- Executes transfer
- Replays same token 100 more times
- Drains 5,000 USDC with one approval
With single-use enforcement:
- First execution: token marked as consumed
- Second attempt: "Token already used" → REJECTED
Time-Delay Attack
Without expiry:
- Agent gets approval during business hours
- Waits until 3am when no one is monitoring
- Executes transaction
With 60-second expiry:
- Token expires before execution window
- Agent must re-request approval → REJECTED
Performance Considerations
Two-gate adds latency. Here's what to expect:
| Operation | Typical Latency |
|---|---|
| Gate 1 (Policy Check) | 20-50ms |
| Gate 2 (Verification) | 10-30ms |
| Total overhead | 30-80ms |
For most agent use cases, this is negligible compared to blockchain confirmation times (seconds to minutes). The security benefit far outweighs the latency cost.
Optimisation options:
- Gate 2 can run locally (SDK-side verification) for lower latency
- Batch operations can share a single Gate 1 call
- Caching for repeated recipient/amount patterns
Comparison to Other Approaches
| Approach | Key Location | Tampering Prevention | Custody Risk |
|---|---|---|---|
| Two-Gate (PolicyLayer) | Your server | ✅ Cryptographic | None |
| MPC Wallets | Distributed | ❌ No policy binding | Shared |
| Multisig | Multiple parties | ❌ No policy binding | Multiple custodians |
| Smart Contract Guards | On-chain | ✅ On-chain enforcement | None |
| Custodial APIs | Third party | ❌ Trust-based | Full custody |
Why not smart contract guards?
On-chain enforcement works but has drawbacks:
- Gas costs for every policy check
- Policy changes require contract upgrades
- Limited policy complexity (gas constraints)
- No off-chain audit trail
Two-gate gives you the security of cryptographic binding without the on-chain overhead.
The Security Guarantee
Two-gate enforcement provides mathematical proof that:
- The transaction that was signed is exactly what was approved
- The approval was used exactly once
- The approval was used within the valid time window
No trust required. No custody required. Just cryptography.
Related reading:
Ready to secure your AI agents?
- Quick Start Guide - Get running in 5 minutes
- GitHub - Open source SDK
Top comments (0)