# Static signatures bound to caller revert under ERC-4337, causing DoS

Sequence ERC4337v07.validateUserOp self-calls isValidSignature, so caller-bound static signatures compare against the wallet instead of the EntryPoint and always revert, DoSing valid UserOps.

- Payout: Contest reward
- Severity: medium
- Program: Sequence
- Credited: Agontuk
- Disclosed: 2025-11-21
- Write-up quality: 6/10
- Original: https://code4rena.com/reports/2025-10-sequence#m-02
- Library page: https://bugbountylibrary.com/r/c4%3A2025-10-sequence%3AM-02
- Tags: domain:web3 impact:dos kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:auth-bypass vuln:dos

**Target:** ERC-4337 wallet module (ERC4337v07 / BaseAuth signature validation)
**Root cause:** validateUserOp() verifies signatures via an external self-call this.isValidSignature(), so msg.sender inside BaseAuth.signatureValidation() is the wallet, not the EntryPoint; the caller-binding check addr != msg.sender then fails for static signatures bound to the EntryPoint.
**Steps:**
1. Configure a static signature bound to the EntryPoint: `setStaticSignature(opHash, address(entryPoint), expiry)`
2. Build a PackedUserOperation using the static-signature flag `0x80`
3. Call `validateUserOp(userOp, userOpHash, 0)` pranked as the EntryPoint
4. Observe revert `BaseAuth.InvalidStaticSignatureWrongCaller(opHash, wallet, entryPoint)` because msg.sender is the wallet
**How found:** Code reading of the call path ERC4337v07.validateUserOp → this.isValidSignature → BaseAuth.signatureValidation, noticing the external self-call changes msg.sender to the wallet and breaks the caller-binding comparison.
**Exploitation:** Any ERC-4337 flow relying on static signatures with a non-zero expected caller (e.g. EntryPoint-bound approvals) deterministically reverts, denying valid UserOperations; validateUserOp also reverts instead of returning 0x00000000, violating ERC-1271 expectations.
**Insight:** When a contract verifies signatures via an external self-call, msg.sender inside the verifier becomes the contract itself; any caller-binding logic (expected-caller checks) silently breaks for callers like the EntryPoint.
