DEV Community

amirjmb1
amirjmb1

Posted on

Ephemeral Autonomy: Securing On-Chain AI Agents with ERC-7702 and Scoped Session Keys

Giving an autonomous AI agent an unconstrained private key creates critical attack vectors: prompt injection, model hallucinations, and RPC interception. Traditional ERC-4337 accounts solve this via custom validator modules, but require migrating assets into an abstract contract wallet.

With ERC-7702, an existing Externally Owned Account (EOA) can delegate its code execution to an implementation contract for a single transaction or session using the EIP-7702 authorization list format:

Authorization Tuple = (chainId, contractAddress, nonce, yParity, r, s)
Enter fullscreen mode Exit fullscreen mode

When evaluated, the EVM prefixes the account bytecode with 0xef01 followed by the designated code address. We can deploy a dedicated AgentSessionValidator contract that enforces temporal limits, target contract whitelisting, and daily spending allowances.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

contract AgentSessionValidator {
    struct SessionConfig {
        address agentKey;
        uint48 validUntil;
        uint96 spendLimit;
        uint96 totalSpent;
        bytes4 allowedSelector;
        address allowedTarget;
    }

    mapping(address => mapping(bytes32 => SessionConfig)) public sessions;

    error SessionExpired();
    error UnauthorizedTarget();
    error SpendLimitExceeded();

    function executeWithSession(
        bytes32 sessionId,
        address target,
        uint256 value,
        bytes calldata payload,
        bytes calldata agentSignature
    ) external payable returns (bytes memory) {
        SessionConfig storage config = sessions[msg.sender][sessionId];

        if (block.timestamp > config.validUntil) revert SessionExpired();
        if (target != config.allowedTarget) revert UnauthorizedTarget();
        if (bytes4(payload[:4]) != config.allowedSelector) revert UnauthorizedTarget();
        if (config.totalSpent + value > config.spendLimit) revert SpendLimitExceeded();

        bytes32 digest = keccak256(abi.encodePacked(block.chainid, target, value, payload));
        bytes32 ethSignedDigest = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", digest));
        address recovered = ecrecover(ethSignedDigest, uint8(agentSignature[64]), bytes32(agentSignature[:32]), bytes32(agentSignature[32:64]));
        require(recovered == config.agentKey, "Invalid Agent Sig");

        config.totalSpent += uint96(value);

        (bool success, bytes memory result) = target.call{value: value}(payload);
        require(success, "Execution Failed");
        return result;
    }
}
Enter fullscreen mode Exit fullscreen mode

Ephemeral Key Lifecycle

  1. Instantiation: The human user signs an EIP-712 payload authorizing an ephemeral agentKey (generated in memory on the agent's isolated runtime) with strict execution boundaries (validUntil = block.timestamp + 1800, spendLimit = 0.5 ether).
  2. Execution: The agent queries an on-chain DEX or lending market, computes the optimal route, signs the calldata using its memory-bound key, and broadcasts via an ERC-7702 authorization batch.
  3. Revocation & Expiry: Once completed or upon TTL expiry, the session invalidates automatically. A single on-chain nullifier write can kill the session instantly if an anomaly is detected by an external watchdog.

Top comments (0)