# twTAP.participate() can be permanently frozen due to lack of access control on host-chain-only operations

twTAP.participate() lacked host-chain-only access control, letting an attacker mint a colliding tokenId on a non-host chain and bridge it to permanently DoS minting on the host chain.

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

**Target:** twTAP ONFT721 governance contract (Solidity, LayerZero)
**Root cause:** participate() has no host-chain-only access control, and mintedTWTap is not synchronized across chains, so the same tokenId can be minted independently on a non-host chain and then bridged to the host chain via ONFT721 _creditTo.
**Steps:**
1. Start with mintedTwTap == 0 on all chains; next tokenId is 1.
2. On a non-host chain, call `participate(attacker, 1 TAP, duration)` to mint twTAP tokenId 1.
3. Call `twTAP.sendFrom(...)` to bridge tokenId 1 to the host chain.
4. Host chain _creditTo sees tokenId 1 does not exist and _safeMint's it without incrementing mintedTwTap.
5. Host chain now has tokenId 1 but mintedTwTap == 0; any `participate()` reverts on `_safeMint` for existing tokenId 1, permanently DoSing minting.
6. Attacker can bridge back and exit to recover locked TAP; host chain stays frozen.
**How found:** Code review noting participate() lacks a host-chain modifier and that mintedTWTap is per-chain unsynchronized, then tracing ONFT721 _creditTo to see it mints arbitrary tokenIds without incrementing the counter.
**Exploitation:** Attacker locks minimal TAP on a non-host chain to mint a twTAP with the host chain's next tokenId, bridges it via LayerZero ONFT721 sendFrom to the host chain where _creditTo mints the colliding tokenId without bumping mintedTWTap, then can bridge back to reclaim TAP while leaving the host chain's participate() permanently reverting.
**Escalation:** Repeatable even when mintedTwTap > 0 by repeatedly minting on non-host chains until the required next tokenId is obtained.
**Insight:** For omnichain NFTs with per-chain auto-incrementing tokenId counters, check whether minting is restricted to a single canonical chain; any chain that can mint locally can pre-empt the host chain's next tokenId and bridge it in to collide.
