# Telcoin CloneableProxy storage collision enables reinitialization and TEL drain

Telcoin's CloneableProxy storage slot 0 collision let an attacker reinitialize the proxy to a malicious implementation and drain ~1.24M TEL.

- Payout: Real-world hack
- Severity: high
- Program: Telcoin
- Analysis by: DeFiHackLabs
- Disclosed: 2023-12-25
- Write-up quality: 7/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2023-12/Telcoin_exp.sol
- Library page: https://bugbountylibrary.com/r/dhl%3A20231225-telcoin
- Tags: area:web3 domain:web3 impact:funds-loss kind:incident platform:defihacklabs sev:high tech:evm tech:solidity technique:source-review vuln:access-control vuln:misconfiguration

**Target:** CloneableProxy upgradeable proxy contract on Polygon
**Root cause:** The proxy's implementation address and the Initializable _initialized/_initializing flags shared packed storage slot 0; writing the implementation address overwrote the initialization flags, so initialize() could be called again.
**Steps:**
1. Fork Polygon at block 51546495
2. Read slot 0 of CloneableProxy 0x56BCADff30680EBB540a84D75c182A5dC61981C0; note _initialized/_initializing bytes
3. Call `CloneableProxy.initialize(address(this), abi.encodePacked(this.transferTELFromCloneableProxy.selector))` to set implementation to attacker contract and re-run initializer
4. Initializer delegatecalls attacker's transferTELFromCloneableProxy, which does `TEL.transfer(msg.sender, TEL.balanceOf(address(CloneableProxy)))`
5. Confirm slot 0 flags now set and subsequent initialize reverts
**How found:** Observation that the proxy stores the implementation address in the same packed slot as OpenZeppelin Initializable's _initialized/_initializing booleans, allowing re-initialization after the implementation was set.
**Exploitation:** Attacker called initialize() on the already-initialized proxy, overwriting the implementation pointer (which collided with the init flags in slot 0) to a malicious contract, then triggered the delegatecall to transfer all TEL held by the proxy to the attacker.
**Insight:** When auditing upgradeable proxies, check whether the implementation address slot overlaps Initializable's packed flags; any write to the implementation can reset init state and re-open initialize().
