Tornado.cash is a recently announced dApp on Ethereum that allows private transactions on the otherwise public Ethereum network. Private transactions have been a lot sought after feature on Ethereum, with many projects developing such features.
Tornado.cash by Peppersec - Private Ethereum Transactions
Tornado.cash is a recently announced dApp on Ethereum that allows private transactions on the otherwise public Ethereum network. Private transactions have been a lot sought after feature on Ethereum, with many projects developing such features. Private transactions are a transfer of funds that provide a measure of privacy in the otherwise quite-public Ethereum network. In the case of Tornado.cash, the measure of privacy is in disconnecting between the entity sending the funds, and the one receiving the funds.
To do this, Tornado.cash uses a mixer contract, in which the funds mix together. Using Zero-knowledge-proofs, Tornado.cash provides mechanisms for deposits to and withdrawal from this mixer contract while hiding the relationship between the sender and the receiver. Each withdrawal could be from any previous deposit. The Tornado.cash contract is designed to be decentralized and non-custodial, leaving users in full control of their funds throughout the process. Under the Tornado.cash implementation, the operator of the mixer receives a predetermined fee for each transaction.
The Tornado.cash project is an elegant solution to enabling somewhat private transactions over Ethereum, and uses existing technologies and is already available for use today on the mainnet. The Tornado.cash team have highlighted the project is still in beta phase, and use is still risky. This project is a great example of community projects and their benefit to the entire ecosystem, pushing the technology to its extremes.
Reviewing the Tornado.cash contracts, we can see once again proof that truly decentralized applications are a difficult thing to create. While we have no doubt the team had the greatest of intentions, constructing systems that are secure against their own creators is a challenging task.
Reviewing the contracts in-depth, our analysis shows the current contract implementation allows the contract's operator to halt all withdrawals from the mixer. The full technical details are available below. The direct meaning of this issue is that the Tornado.cash team or any future operator of the mixer can freeze all funds currently in the mixer. We're confident the team has no intention to use this bug to their advantage, and the team has been very vocal that the contracts are still being reviewed.
Nevertheless, we see this as proof once again, that writing contracts that are safe and decentralized is a challenging task, and can be impacted by even the slightest issue.
About Valid Network
Valid Network provides a comprehensive cybersecurity platform for DApps (Decentralized Applications). Valid Network's unique value proposition is well defined in its DevSecOps approach that protects organizations from the first line of code developed, through supplying assurance and governance for live business transactions. Valid Network’s experience in distributed systems brought the team to exhibit several breakthrough technologies for detection, monitoring, and enforcement.
Full Issue Technical Details
Tornado.cash contract's withdraw function transfers a constant allowed value minus a fee to the receiver and then transfers the fee to the contract's operator. The contract's operator is an address determined in the constructor, and that can be changed only by the current operator. If the contract's operator itself happened to be a contract where Ether can not be received, e.g. there is no payable function in the contract or the existing payable function reverts, or the payable function is gas heavy, then the whole transaction would be reverted, including the receiver's withdrawal. In other words, funds that have been deposited are locked until the flawed operator contract is replaced, and it puts the operator in a spot of a centralized single point of failure component.
Put the operator's fee transfer logic in a different function, that can only be invoked in a different transaction, and this way eliminate the receiver dependence on the operator's contract.