coinbase / coinbase/agentkit

Optional pre-sign transaction guard: catch approval/Permit2 drains before the wallet signs

Open
#1,360 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
1.3k
Forks
815
Avg merge
13h 31m
Merged PRs (30d)
2

Description

### Summary

Sharing a small, **optional** pre-sign safety hook in case it is useful to AgentKit users, and to get the team's read on whether it belongs as a documented pattern. Feedback very welcome — including "this belongs in a wallet layer, not here."

*Disclosure: I maintain [chain-signer](https://github.com/Kevthetech143/chain-signer), the library referenced below. This is an optional integration suggestion, not a dependency ask.*

### The gap

AgentKit's wallet providers screen recipients (sanctions / known-bad addresses), which is great. What they don't do today is decode the **calldata** of the transaction the agent is about to sign. Most agent fund-loss in 2026 hasn't come from sending to a sanctioned address — it has come from an agent being talked into signing an **unlimited `approve()`**, a **`setApprovalForAll(true)`**, a **Permit2** allowance, or the same drain hidden inside a `multicall` / Safe / ERC-4337 `execute`. A recipient check doesn't see any of that, because the malicious party is the *spender in the calldata*, not the `to` of the tx. (Write-up with reproduced 2026 incident shapes: https://gist.github.com/Kevthetech143/f4b940b2b31d457bd593c3d6df9f65c4)

### A small, dependency-light option

`chain-signer` is a pip-installable, **offline, no-API-key, no-network** static decoder. `preflight(tx)` decodes an unsigned EVM tx and returns HIGH/MED/LOW flags for the known drain patterns (unlimited/large approval, `increaseAllowance`, `setApprovalForAll`, ERC-20 `transferFrom`, ERC-721/1155 `safeTransferFrom`, ERC-2612/DAI/Permit2 permits, proxy `upgradeTo`, EIP-7702 delegation, and drains nested in `multicall` / Multicall3 / Safe `multiSend` / 4337 `execute`). It's a static complement to recipient screening and to simulation — not a replacement — and it runs in-process with no external call.

### Proposed shape (opt-in wrapper, verified against `coinbase-agentkit==0.7.4`)

```python
from chain_signer import preflight
from web3.types import TxParams
from coinbase_agentkit.wallet_providers import EthAccountWalletProvider # or CdpEvmWalletProvider

class PreflightBlocked(Exception): ...

def preflight_guard(tx: dict, *, on_block: str = "raise"):
report = preflight(tx) # offline, no key, no network
highs = [f for f in report.get("risk_flags", []) if f.get("severity") == "HIGH"]
if highs and on_block == "raise":
raise PreflightBlocked("blocked before signing: " + ", ".join(f["code"] for f in highs))
return None if highs else tx

class GuardedEthAccountWalletProvider(EthAccountWalletProvider):
def send_transaction(self, transaction: TxParams):
preflight_guard(dict(transaction), on_block="raise") # raises BEFORE sign + broadcast
return super().send_transaction(transaction)
```

Behavior (real provider instantiated, `send_transaction` called on a malicious unlimited `approve()` — raised before any broadcast):

```
BLOCKED pre-broadcast: chain-signer blocked a HIGH-risk tx before signing: unlimited_approval
```

Off by default; zero behavior change unless a user opts in.

### Honest limits (stated up front)

This is **static** decoding, so it won't catch a novel/obfuscated drain it can't decode (those get a LOW "unknown" flag, not a block); it's EVM-only; and it does **not** stop a *redirected legitimate transfer* (moving real funds to an attacker) — that's a recipient-allowlist / value-cap concern, which AgentKit's policy layer already addresses and which chain-signer's separate `check_action` gate also covers. Best used alongside recipient screening + simulation for high-value actions.

Happy to open a PR adding this as a documented optional example if the team thinks it fits, or to just leave it here as a pattern for anyone who wants it.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.