# Possibility to drain SavingsAccount contract assets

switchStrategy trusts attacker-supplied _currentStrategy contract; rogue getSharesForTokens/unlockTokens returns full SavingsAccount balance, re-locking stolen tokens as attacker shares.

- Payout: Audit contest
- Severity: high
- Program: Sublime
- Found by: kemmio
- Disclosed: 2022-02-14
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2021-12-sublime-findings/issues/41
- Library page: https://bugbountylibrary.com/r/c4%3A2021-12-sublime%3AH-08
- Tags: area:web3 domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:source-review vuln:access-control vuln:business-logic

**Target:** SavingsAccount.sol switchStrategy()
**Root cause:** switchStrategy() calls IYield(_currentStrategy).getSharesForTokens() and unlockTokens() on an unvalidated, caller-supplied strategy address, so a malicious contract controls the returned token amount and share accounting.
**Steps:**
1. Deploy rogue contract implementing getSharesForTokens() returning 0 and unlockTokens() returning IERC20(token).balanceOf(msg.sender) (or msg.sender.balance for ETH).
2. Call `switchStrategy(_token, _amount>0, ROGUE_ADDRESS, validNewStrategy)` so the `_amount != 0` require passes.
3. getSharesForTokens returns 0, so `balanceInShares[msg.sender][_token][ROGUE].sub(0)` does not underflow.
4. unlockTokens returns the contract's full token balance as `_tokensReceived`.
5. Contract approves/locks `_tokensReceived` into `_newStrategy` and credits `_sharesReceived` to attacker's balanceInShares.
**How found:** Code review of switchStrategy: noticed _currentStrategy is never checked against the strategy registry (unlike _newStrategy), and that _amount is overwritten by an external call's return value before the balance subtraction, enabling a zero-value underflow bypass.
**Exploitation:** Attacker registers a rogue strategy, invokes switchStrategy pointing _currentStrategy at it, and the contract treats the entire SavingsAccount token balance as the attacker's unlocked position, re-locking it under the attacker's shares for later withdrawal.
**Insight:** When a function validates one address parameter against a registry, check whether sibling address parameters (here _currentStrategy) skip the same check; also watch for user-supplied amounts overwritten by external-call return values before accounting math.
