Reproduced Exploit

Etherspot CredibleAccountModule — session-key approval drains the wallet

Session-key call validation allows any ERC20 approve target. The key owner chooses itself as spender, then calls transferFrom to remove every token held by the smart wallet rather than only the locked allocation.

Jan 2025Otheraccess-control2 min read

Chain

Other

Category

access-control

Date

Jan 2025

Source

AuditVault

EVM Playground

Source-level debugger — step opcodes and Solidity in sync

evm-hack-analyzer

The attack is replayed in an in-browser EVM preloaded with the exact dumped fork state. The execution tree shows every call; step by Solidity line or by opcode across all depths — source, Stack, Memory, Storage, Balances (native / ERC-20 / NFT), Transient storage and Return value stay in sync. Click a tree node, opcode, or source line to jump. No backend, no live RPC.

Loading fork state…

Source & credit. Reproduction of a public audit finding curated by AuditVault — the original finding: 62847-c-01-sessionkey-owner-can-drain-the-smart-wallet-shieldify-n. Standalone Foundry PoC and full write-up: 62847-c-01-sessionkey-owner-drain-smart-wallet_exp in the evm-hack-registry mirror.


Vulnerability classes: vuln/access-control/missing-owner-check · vuln/logic/missing-validation

Reproduction: local synthetic Foundry reduction; the complete passing trace is in output.txt.

Key info#

FieldValue
LossA session key approves itself and transfers all 1,000 synthetic wallet tokens.
Vulnerable contractCredibleAccountModule.validateApproval in test/62847-c-01-sessionkey-owner-drain-smart-wallet.sol
Attacker EOA0x1111111111111111111111111111111111111111
Attack contractExploit
Attack txLocal Foundry Exploit.run()
Chain · block · dateEthereum model · block 0 · synthetic
CompilerSolidity ^0.8.24
Bug classUnrestricted ERC20 approve spender

TL;DR#

Session-key call validation allows any ERC20 approve target. The key owner chooses itself as spender, then calls transferFrom to remove every token held by the smart wallet rather than only the locked allocation.

Background#

CredibleAccountModule sessions are intended to constrain both callable selectors and token amounts. approve is safe only when the spender is the module and the amount is bounded by the session.

The vulnerable code#

SOLIDITY
function validateApproval(address /*spender*/, uint256 /*amount*/) external pure returns (bool) {
    // @> VULN: approve calls are accepted without requiring the module as spender.
    return true;
}

See the complete reduction in test/62847-c-01-sessionkey-owner-drain-smart-wallet.sol.

Root cause#

The selector allowlist treats all approve calls as equivalent and does not decode the spender (or amount). A valid session signature consequently grants an unlimited delegated-transfer primitive.

Preconditions#

  • The smart wallet holds ERC20 tokens.
  • A session key can submit an approve call.
  • The validator does not require the module as spender or enforce the locked amount.

Attack walkthrough#

  1. Exploit.run() mints 1,000 units to SmartWallet.
  2. The session call approves the attacker contract for 1,000 units.
  3. transferFrom moves the full balance; the passing assertion is at output.txt:4.

Diagrams#

flowchart LR W[Smart wallet: 1000 tokens] -->|session approve attacker| A[Attacker spender] A -->|transferFrom| D[Wallet balance 0]

Remediation#

Decode every approve call, require spender == address(CredibleAccountModule), and cap the approved amount to the session's locked token amount. Apply the same validation to batch execution.

How to reproduce#

BASH
cd evm-hack-registry/62847-c-01-sessionkey-owner-drain-smart-wallet_exp
forge test -vvvvv

Sources#

Reference: https://github.com/shieldify-security/audits-portfolio-md/blob/main/Etherspot-GasTankPaymasterModule-Extended-Security-Review.md


Sources & further analysis#

Reproductions & code

Alerts & third-party analyses

  • Web3Sec X hacked database: search.
  • Rekt leaderboard: search.
  • Solodit incident search: search.

These dashboards index community alerts tweets, post-mortems, and independent write-ups. Reach them through the protocol name above to cross-check this reproduction against other analyses.