# All funds can be stolen from FixedStrikeOptionTeller using a token with malicious decimals

Attacker deploys option with malicious payout token whose decimals() changes between create and exercise, minting options for 0 quote tokens then redeeming for huge quote payout, draining the teller.

- Payout: Contest reward
- Severity: high
- Program: Bond
- Credited: Juntao
- Disclosed: 2023-06-26
- Write-up quality: 8/10
- Original: https://github.com/sherlock-audit/2023-06-bond-judging/issues/90
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-06-bond%3AH-2
- Tags: domain:web3 impact:funds-loss kind:contest platform:sherlock sev:high tech:evm tech:solidity technique:chained technique:source-review vuln:accounting-error vuln:business-logic

**Target:** FixedStrikeOptionTeller option contract (Solidity)
**Root cause:** quoteAmount is computed via amount_.mulDiv(strikePrice, 10 ** payoutToken.decimals()) reading decimals() live on each call; an attacker-controlled payout token can return different decimals at create vs exercise/reclaim time.
**Steps:**
1. Deploy malicious payout token whose decimals() returns a large value (e.g. 77) on first call and a small value (e.g. 0) later.
2. Call `FixedStrikeOptionTeller.deploy` with malicious payout token, DAI as quote token, put option type.
3. Call `create(optionToken, X)` while decimals() is large: `quoteAmount = X.mulDiv(strikePrice, 10**77)` = 0, so 0 DAI pulled but X option tokens minted.
4. Flip decimals() to small value; call `exercise(optionToken, X)` or `reclaim`: `quoteAmount = X.mulDiv(strikePrice, 10**0)` yields huge DAI transfer to attacker.
5. Repeat with other ERC20 quote tokens held by the teller to drain all balances.
**How found:** Code review of create/exercise/reclaim: noticed decimals() is fetched live from an attacker-deployable payout token rather than cached at deploy time, making the quoteAmount divisor attacker-controlled and inconsistent across calls.
**Exploitation:** Attacker needs only gas: deploy a malicious ERC20 payout token with controllable decimals(), deploy an option against a quote token the teller holds, mint options for free via create with inflated decimals, then exercise/reclaim with deflated decimals to extract the teller's entire quote-token balance.
**Escalation:** Same primitive repeated per quote token drains every ERC20 held by the shared teller contract.
**Insight:** When a permissionless factory lets users supply tokens, any live external call (decimals, price, oracle) used in share/amount math is attacker-mutable between mint and redeem; check for TOCTOU on token metadata and cache it at registration.
