# Unsigned validity window metadata

AtomWallet recovers signer over userOpHash only, leaving appended validUntil/validAfter unauthenticated, so relayers can rewrite a signed op's validity window and replay it later.

- Payout: Contest reward
- Severity: medium
- Program: Intuition
- Credited: v12
- Disclosed: 2026-04-27
- Write-up quality: 7/10
- Original: https://code4rena.com/reports/2026-03-intuition#m-01
- Library page: https://bugbountylibrary.com/r/c4%3A2026-03-intuition%3AM-01
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:auth-bypass vuln:signature-replay

**Target:** ERC-4337 smart wallet signature validation (AtomWallet._validateSignature)
**Root cause:** validUntil/validAfter are appended to userOp.signature but excluded from the EIP-191 hashed message, so they are not cryptographically bound to the signer.
**Steps:**
1. Observe a signed userOp whose signature is 77 bytes: 65-byte ECDSA sig + 12 bytes (validUntil, validAfter).
2. Keep the 65-byte ECDSA signature unchanged; overwrite the trailing 12 bytes with a new validUntil/validAfter window.
3. Submit the modified userOp; _validateSignature extracts the new window and recovers the signer over userOpHash only.
4. Recovered address still equals owner(), so validation passes and the op executes outside the signer's intended timeframe.
**How found:** Code reading of _validateSignature: noticed the 12-byte validity suffix is parsed from userOp.signature but the recovered hash is computed only over userOpHash with the EIP-191 prefix, so the metadata is never signed.
**Exploitation:** A relayer or observer of a signed userOp rewrites the trailing validity metadata to extend or remove expiry, then resubmits later; the unchanged ECDSA signature still recovers to owner(), enabling transfers/actions after the user believed the request expired.
**Insight:** In ERC-4337 wallets, any bytes appended to userOp.signature and parsed as policy (time windows, nonces, gas limits) must be folded into the signed digest; check that every field extracted from the signature blob is committed to the hash.
