# TOFT and USDO Modules Can Be Selfdestructed

TOFT/USDO module functions take an attacker-supplied `module` address for delegatecall, letting anyone selfdestruct the module and permanently brick the protocol.

- Payout: Contest reward
- Severity: high
- Program: Tapioca DAO
- Credited: Ack
- Disclosed: 2023-11-16
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2023-07-tapioca-findings/issues/1083
- Library page: https://bugbountylibrary.com/r/c4%3A2023-07-tapioca%3AH-28
- Tags: domain:web3 impact:dos impact:integrity kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:source-review vuln:access-control vuln:dos

**Target:** Solidity module contracts (BaseTOFT*/USDO* modules) using delegatecall
**Root cause:** Public functions accept a `module` address parameter and delegatecall into it without validation, so an attacker-controlled contract can run selfdestruct in the module's context. Module addresses are fixed in the constructor with no setters, so destruction is permanent.
**Steps:**
1. Deploy `Exploit` contract whose fallback calls `selfdestruct(attacker)`.
2. Call e.g. `USDOLeverageModule.leverageUp(module=Exploit, ...)` or any of the listed module functions with the Exploit address as `module`.
3. The delegatecall executes Exploit's fallback in the module's context, selfdestructing the module.
4. All subsequent calls to the module revert; protocol functionality is permanently broken.
**How found:** Code review of module functions: noticed the `module` parameter is user-supplied and used directly as a delegatecall target, then reasoned that a selfdestructing fallback would execute in the module's context and that constructor-set module addresses have no setter, making the damage permanent.
**Exploitation:** Attacker deploys a contract with a selfdestructing fallback and passes its address as the `module` argument to any of the public module entrypoints (leverageUp, market/options/strategy functions). The delegatecall runs the fallback in the module's storage context, destroying the module code. Since BaseTOFT/BaseUSDO store module addresses immutably from the constructor with no setters, the modules cannot be replaced, bricking all dependent calls.
**Insight:** When a function takes an address used as a delegatecall target, check whether it's caller-controlled; a selfdestructing fallback turns arbitrary delegatecall into permanent code destruction, especially damaging when the intended target is fixed in the constructor with no setter.
