# Argent: signature replay and recovery-deadline overflow drains wallets

Argent smart wallet execution module lacked nonce/used-hash checks and deadline enforcement, letting anyone replay years-old owner/guardian signatures to drain wallets via a thin MARK pool.

- Payout: Real-world hack
- Severity: high
- Program: Argent
- Analysis by: DeFiHackLabs
- Disclosed: 2026-10-19
- Write-up quality: 8/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2026-10/Argent_exp.sol
- Library page: https://bugbountylibrary.com/r/dhl%3A20261019-argent
- Tags: area:web3 domain:web3 impact:funds-loss kind:incident platform:defihacklabs sev:high tech:evm tech:solidity technique:chained vuln:access-control vuln:business-logic vuln:signature-replay

**Target:** Smart wallet execution and recovery modules (execute relay, recovery deadline setter)
**Root cause:** The execution module's execute() recovers owner/guardian ECDSA signatures but never consumes a nonce or records the signed-message hash, and does not enforce the signed deadline (which overflows). Separately, the recovery module's deadline setter accepts an attacker period that wraps the recovery deadline into the past, enabling an immediate same-transaction owner change.
**Steps:**
1. Fork mainnet at parent of attack tx (block 26225797 for e545, 26225802 for 5a79).
2. Call recovery deadline setter `0x254a2e49` with `RECOVERY_OVERFLOW_CONFIG` to wrap e545 recovery deadline into the past.
3. Relay years-old guardian signature `SIG_RECOVERY_E545` via `execute(...)` to run `executeRecovery` (selector `0xb0ba4da0`), then call `finalizeRecovery(wallet)` to flip owner in same tx.
4. Flash-borrow 0.5 WETH from Balancer vault `0xBA12...F2C8`.
5. Loop 19 times: push WETH into thin MARK/WETH pair `0x6f23...b6f3`, replay `SIG_SWAP_E545` through `execute()` with wallet-swap payload `0xe92bdbf8` to make wallet buy ~1.06 ETH of MARK at manipulated top, sell MARK back for inflated WETH.
6. Repay flash loan, swap ~20.17 WETH profit to 48,778.499253 USDC.
7. Repeat same flash-loan + replay loop 9 times on 5a79 wallet with `SIG_SWAP_5A79`, each replay making wallet spend 1,000 USDC on MARK, netting 1,877.419234 USDC.
**How found:** Recognized that the execute() relay path recovers signatures but never consumes a nonce or records the message hash, and that the signed deadline is unchecked and overflows; combined with a recovery deadline setter whose attacker-supplied period wraps the deadline into the past. Years-old signatures were already public on-chain.
**Exploitation:** Attacker flash-borrows WETH from Balancer, uses a recovery-deadline overflow to force an immediate owner change on the e545 wallet, then replays public years-old owner/guardian signatures through the nonce-less execute() relay to repeatedly force the victim wallets to buy MARK at a manipulated top in a thin MARK/WETH pool while the attacker trades around them, repaying the loan and converting profit to USDC.
**Escalation:** Chained two independent module flaws (recovery-deadline overflow for owner takeover + signature replay for repeated forced trades) and amplified via flash loan and thin-pool price manipulation across two victim wallets.
**Insight:** On smart-wallet relay modules, check whether the signature path consumes a nonce or records the signed-message hash, and whether the signed deadline is actually enforced (integer overflow in deadline math). Also audit recovery deadline setters for period values that wrap the deadline into the past, enabling same-transaction owner changes.

## Proof of concept (copied exactly from the original report)

**Recovery-deadline overflow config argument**

```
bytes32 constant RECOVERY_OVERFLOW_CONFIG =
        0x0000c22e450672894ab6cd8efb11d33f5617839a5bc7dea00c22e450672843a3;
```

**Relay execute() interface with nonce and signatures**

```
function execute(
        address wallet,
        bytes calldata data,
        uint256 nonce,
        bytes calldata signatures,
        uint256 gasPrice,
        uint256 gasLimit
    ) external returns (bool);
```

