# Redacted Cartel Custom Approval Logic Bugfix Review

wxBTRFLY's custom transferFrom read allowance from recipient instead of spender, letting anyone reassign a victim's approval to themselves and drain funds.

- Payout: $560,000
- Severity: critical
- Program: Redacted Cartel
- Credited: Tommaso Pifferi
- Disclosed: 2022-05-29
- Write-up quality: 7/10
- Original: https://immunefi.com/blog/bug-fix-reviews/redacted-cartel-custom-approval-logic-bugfix-review/
- Library page: https://bugbountylibrary.com/r/blog%3Aimmunefi-com-blog-bug-fix-reviews-redacted-cartel-custom-approval-logic-bugfix-review
- Tags: domain:web3 impact:funds-loss kind:bounty platform:blog platform:immunefi sev:critical tech:evm tech:solidity technique:incomplete-fix technique:source-review vuln:business-logic

**Target:** wxBTRFLY ERC-20 token contract (FrozenToken transferFrom)
**Root cause:** Custom transferFrom decreased the allowance of (owner, recipient) instead of (owner, msg.sender), then wrote the reduced value to the (owner, msg.sender) slot, effectively granting the caller the recipient's allowance.
**Steps:**
1. Alice holds 1000 wxBTRFLY and approves aliceContract to spend 1000.
2. Bob calls `wxBTRFLY.transferFrom(Alice, aliceContract, 0)` — no tokens move, but the buggy allowance write grants Bob an allowance of 1000 from Alice.
3. Bob calls `wxBTRFLY.transferFrom(Alice, bob, 1000)` and receives all of Alice's tokens.
**How found:** Researcher read the custom FrozenToken transferFrom implementation and noticed the allowance read used the recipient address while the write used msg.sender, a mismatch versus the OpenZeppelin reference implementation.
**Exploitation:** Attacker needs only a victim who has granted any allowance to a third-party spender. By calling transferFrom with amount 0 and the spender as recipient, the attacker's own allowance slot is set to the victim's existing allowance, then a second transferFrom moves the victim's full balance to the attacker. No capital required.
**Insight:** When a protocol forks or hand-rolls ERC-20 instead of using OpenZeppelin, diff the approve/transferFrom allowance bookkeeping line-by-line: check that the same (owner, spender) key is read and written, and test transferFrom with amount 0 to a third-party spender to see whose allowance changes.
