Reproduced Exploit
Cover Protocol — unlimited approve lets an attacker take 1000 DAI off the router
addCoverAndCreatePools pulls the depositor's collateral onto the router and approves _protocol for the maximum uint256. _protocol is not checked. The attacker's addCover returns false, so the 1,000 DAI stays on the router, and the attacker transferFroms it.
Chain
Other
Category
access-control
Date
Jan 2021
Source
AuditVault
EVM Playground
Source-level debugger — step opcodes and Solidity in sync
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.
Source & credit. Reproduction of a public audit finding curated by AuditVault — the original finding: 28663-possibility-to-steal-tokens-from-the-contract-balance-mixbyt. Standalone Foundry PoC and full write-up: 28663-possibility-to-steal-tokens-from-the-contract-balance-mixbyt_exp in the
evm-hack-registrymirror.
Vulnerability classes: vuln/access-control/missing-auth · vuln/logic/missing-validation
Reproduction: a self-contained Foundry PoC that compiles and runs offline with only
forge-std— no fork and no RPC. Trace: output.txt. PoC: test/28663-possibility-to-steal-tokens-from-the-contract-balance-mixbyt_exp.sol.
Key info#
| Impact | HIGH — the attacker receives N = 1,000 DAI from the router |
| Protocol | Cover Protocol CoverRouter |
| Vulnerable code | approve(_spender, uint256(-1)) with no protocol check |
| Bug class | Unlimited allowance plus a failed addCover that still succeeds |
| Finding | MixBytes — Cover Protocol Peripheral, 11 January 2021 · id 28663 |
| Report | Cover Protocol Peripheral |
| Source | AuditVault finding |
| Status | Reproduced. uint256(-1) is written as type(uint256).max so solc 0.8 accepts it. |
| Compiler | solc 0.8.27, cancun, via IR |
TL;DR#
addCoverAndCreatePools pulls the depositor's collateral onto the router and approves _protocol for the maximum uint256. _protocol is not checked. The attacker's addCover returns false, so the 1,000 DAI stays on the router, and the attacker transferFroms it.
The depositor ends at 0. The router ends at 0. The attacker holds 1,000 DAI.
The vulnerable code#
if (_token.allowance(address(this), _spender) < _amount) {
// @> VULN: audited approve(_spender, uint256(-1))
_token.approve(_spender, type(uint256).max);
}
The audited source is Solidity 0.7 and writes uint256(-1). That literal does not compile on 0.8. The value is the same maximum.
Root cause#
Two missing checks stack. The spender of the unlimited allowance is whatever address the caller passed as _protocol. And a false return from addCover does not revert or refund, so the tokens the router just pulled are left sitting under that allowance.
Preconditions#
- A depositor holds 1,000 DAI and calls the router with the attacker's address as the protocol.
addCoveron that address returns false and does not move the tokens itself.
Attack walkthrough#
- Mint 1,000 DAI to the depositor.
- The depositor approves the router and calls
addCoverAndCreatePools(attacker, DAI, 1000). - The router pulls 1,000 DAI.
- The allowance is below the amount, so the router approves
type(uint256).maxto the attacker. addCoverreturns false. The DAI is still on the router.- The attacker
transferFroms 1,000 DAI to themselves.
Control: the router accepts only one protocol address and reverts before the pull when the caller names anyone else. The depositor still holds 1,000 DAI.
Diagrams#
Impact#
The depositor loses 1,000 DAI. The attacker holds it. Any later balance left on the router is exposed to the same allowance.
Remediation#
Approve only the amount this call needs, and only to a known protocol. If addCover returns false, revert and send the collateral back.
Sources#
- AuditVault finding 28663
- MixBytes Cover Protocol Peripheral, 11 January 2021
- CoverRouter.sol at d5b37e34
Taxonomy#
vuln/access-control/missing-check·vuln/logic/missing-validation
Sources & further analysis#
Reproductions & code
- Standalone PoC + full trace: 28663-possibility-to-steal-tokens-from-the-contract-balance-mixbyt_exp (evm-hack-registry mirror).
- AuditVault finding: 28663-possibility-to-steal-tokens-from-the-contract-balance-mixbyt.
Alerts & third-party analyses
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.