# Illuminate PT redeeming allows for burning from other accounts

Redeemer.redeem() checks msg.sender's PT balance but burns from attacker-supplied `o` address, letting any holder burn others' shares and drain underlying tokens.

- Payout: Contest reward
- Severity: high
- Program: Illuminate
- Credited: hyh
- Disclosed: 2022-08-23
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2022-06-illuminate-findings/issues/387
- Library page: https://bugbountylibrary.com/r/c4%3A2022-06-illuminate%3AH-13
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:solidity technique:source-review vuln:access-control vuln:business-logic

**Target:** Redeemer.sol redeem() / ERC5095 principal token
**Root cause:** redeem() reads amount from token.balanceOf(msg.sender) but calls token.burn(o, amount) with an unvalidated user-supplied `o` address, so the burn debits a different account than the one whose balance was checked.
**Steps:**
1. Attacker holds X Illuminate PT and calls Redeemer.redeem(u, m, p, o=victim) with p=Illuminate.
2. redeem() computes amount = token.balanceOf(msg.sender) = X.
3. redeem() calls token.burn(o, X) which _burn(victim, X), reducing victim's balance by X.
4. redeem() transfers X underlying tokens from lender to attacker, so attacker extracts value while victim's PT is destroyed.
**How found:** Code reading of redeem(): noticed the balance check uses msg.sender while the burn uses the separate `o` parameter, a mismatch between the account verified and the account debited.
**Exploitation:** Attacker needs only a small PT balance; by passing any victim address as `o`, the burn debits the victim while the underlying transfer goes to the attacker, repeating across all holders to drain the system's underlying tokens.
**Escalation:** Repeat across every PT holder to extract the full underlying backing of the market.
**Insight:** When a function both checks a balance and mutates it, verify the same address is used for both; a user-supplied recipient/from parameter that isn't cross-checked against msg.sender is a classic accounting mismatch.
