Reproduced Exploit

Royco ERC4626i — Missing permissions check in withdraw and redeem

1. ERC-4626 redeem(shares, receiver, owner) must require msg.sender == owner or sufficient allowance. 2. Royco's ERC4626i omits that check entirely. 3. An attacker calls redeem(bobShares, attacker, bob) and receives Bob's underlying assets. 4. Bob's shares are burned; vault is drained of Bob's depo…

Aug 2024Otheraccess-control2 min read

Chain

Other

Category

access-control

Date

Aug 2024

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: 46674-missing-permissions-check-in-withdraw-and-redeem-functions-i. Standalone Foundry PoC and full write-up: 46674-missing-permissions-check-in-withdraw-and-redeem-functions-i_exp in the evm-hack-registry mirror.


Vulnerability classes: vuln/access-control/missing-modifier · direct-drain · reward-accounting

Reproduction: self-contained Foundry PoC, offline, forge-std only. Full trace: output.txt. PoC: test/46674-missing-permissions-check-in-withdraw-and-redeem-functions-i_exp.sol.


Key info#

ImpactHIGH — anyone can redeem any owner's shares and steal underlying
ProtocolRoyco — ERC4626i
Vulnerable codeERC4626i.redeem / withdraw — no owner/allowance check
Bug classMissing access control on share burn / asset transfer
FindingCantina — Royco, Aug 2024 · #46674 · reporter Kurt Barry
Reportcantina_royco_august2024.pdf
SourceAuditVault
StatusAcknowledged — ERC4626i being rewritten
Compiler^0.8.24 (PoC)

TL;DR#

  1. ERC-4626 redeem(shares, receiver, owner) must require msg.sender == owner or sufficient allowance.
  2. Royco's ERC4626i omits that check entirely.
  3. An attacker calls redeem(bobShares, attacker, bob) and receives Bob's underlying assets.
  4. Bob's shares are burned; vault is drained of Bob's deposit.

The vulnerable code#

SOLIDITY
function redeem(uint256 shares, address receiver, address owner) public returns (uint256 assets) {
    balanceOf[owner] -= shares; // @> VULN: no msg.sender==owner / allowance check
    totalSupply -= shares;
    assets = shares;
    asset.transfer(receiver, assets);
}

Fix (solmate ERC4626):

SOLIDITY
if (msg.sender != owner) {
    uint256 allowed = allowance[owner][msg.sender];
    if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares;
}

Root cause#

Share-burn path lacks the standard ERC-4626 authorization check.

Preconditions#

  • Victim holds vault shares (deposited assets).
  • Attacker has no allowance from victim (or any role).

Attack walkthrough#

  1. Bob deposits 1 ether of underlying → 1 ether shares.
  2. Alice calls redeem(1 ether, alice, bob) with no allowance.
  3. Vault burns Bob's shares and transfers 1 ether underlying to Alice.
  4. HARM: full deposit stolen.

Diagrams#

sequenceDiagram participant Bob participant Vault as ERC4626i participant Alice Bob->>Vault: deposit 1 ether Note over Vault: bob shares = 1e18 Alice->>Vault: redeem 1e18 alice bob Note over Vault: no allowance check Vault-->>Alice: 1 ether underlying Note over Bob: shares = 0, funds stolen

Impact#

Direct theft of any depositor's underlying assets by any external account.

Sources#


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.