# Duplication of Balance

Cauldron.stir caches balances in memory, so a self-transfer writes the incremented balance back, duplicating arbitrary ink/art and breaking accounting.

- Payout: Audit contest
- Severity: high
- Program: Yield
- Disclosed: 2021-07-23
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2021-05-yield-findings/issues/16
- Library page: https://bugbountylibrary.com/r/c4%3A2021-05-yield%3AH-01
- Tags: area:web3 domain:web3 impact:funds-loss impact:integrity kind:contest platform:code4rena sev:high tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** Cauldron.stir invoked via Ladle operation
**Root cause:** stir caches balances in memory before decrementing and incrementing; when from == to, the assignment balances[to] = balancesTo writes the added-to balance instead of the neutral net balance.
**Steps:**
1. Call Cauldron.stir via a Ladle operation with from == to (transfer to self).
2. stir reads cached balances for from/to before mutation.
3. Decrement and increment are applied to the same cached slot.
4. balances[to] = balancesTo stores the incremented value, duplicating ink/art.
**How found:** Code review of stir's in-memory balance caching; noticed that a self-transfer makes the from and to cache slots alias, so the write-back uses the incremented balance.
**Exploitation:** Attacker performs a self-transfer through stir, causing the cached balance to be written back with the added amount, minting arbitrary ink or art units out of thin air and corrupting protocol accounting.
**Insight:** In accounting code that caches balances before mutating, always test from == to (and other aliasing cases); a self-transfer can turn a neutral net operation into a duplication.

