# TSS Key Voting Hash Collision

TSS keygen vote digest omits the submitted public key, so the last observer can swap in an attacker-controlled TSS pubkey and drain all cross-chain funds.

- Payout: Contest reward
- Severity: high
- Program: ZetaChain
- Credited: ChristiansWhoHack
- Disclosed: 2024-09-06
- Write-up quality: 8/10
- Original: https://github.com/code-423n4/2023-11-zetachain-findings/issues/133
- Library page: https://bugbountylibrary.com/r/c4%3A2023-11-zetachain%3AH-14
- Tags: domain:web3 impact:funds-loss impact:integrity kind:contest platform:code4rena sev:high tech:go technique:source-review vuln:access-control vuln:business-logic

**Target:** Cosmos SDK module x/crosschain MsgCreateTSSVoter ballot digest
**Root cause:** The ballot digest for MsgCreateTSSVoter is built only from keyGenZetaHeight and status, excluding TssPubkey, so votes for different public keys collide on the same ballot.
**Steps:**
1. Set up 4 observers via ObserverKeeper.SetObserverMapper and SetNodeAccount, enable Keygen at block 10.
2. Submit MsgCreateTSSVoter from observers 1-3 with TssPubkey `Key1`, KeyGenZetaHeight 3, Status Success.
3. Submit MsgCreateTSSVoter from observer 4 with TssPubkey `MaliciousKeyThatOnlyIVotedOn`, same height/status.
4. Observe msg.Digest() == msg4.Digest() == `3-tss-keygen`; ballot finalizes with 100% and GetTSS returns the malicious pubkey.
5. Run via `go test -v ./x/crosschain/keeper/ -run TestTssHashCollision`.
**How found:** Code review of the voting/digest construction: noticed the digest only hashed height and status, hypothesized that two voters submitting different pubkeys would share a ballot, then wrote a Go test with 4 observers to confirm the collision and malicious key adoption.
**Exploitation:** Attacker controls one observer and waits to be the final voter in a keygen round; submits a colliding vote carrying their own TSS pubkey, which becomes the chain's TSS address. Admin then calls MigrateTSSFunds sending all BTC/ETH to the attacker key, and the malicious TSS address passes Connector access control to mint/authorize arbitrary cross-chain transactions.
**Escalation:** Single observer vote escalates to full TSS key control, enabling theft of all custody funds across chains plus forging Connector events to create funds from nothing.
**Insight:** When auditing threshold/multi-party voting, check exactly which fields enter the ballot digest; any field that determines the outcome (here the pubkey) but is excluded from the hash lets a late voter substitute their value while reusing others' votes.
