Non-obvious precautions for DAO security

30 May, 2023
article image
Case Study



The Tornado Cash Governance hack: A closer look

During the ETHDam conference, where our team members were actively discussing ZK-related topics, the blockchain community was shocked by an emergency revelation: the Tornado Cash Governance system had been attacked.

This incident, full of uncertainties, is currently under the scrutiny of many community investigators. Our team has performed a little analysis of the recent Tornado Cash Governance hack. In this article, we aim to walk you through the entire incident, explaining our perspective on what happened, its implications and potential solutions. Let’s delve into the details, understand the gravity of the situation, and talk about the lessons that we have to learn from it.

On May 20, 2023, at exactly 07:25:11 UTC, the Tornado Cash Governance system fell victim to a precisely calculated attack. An unidentified attacker, exploiting a loophole in the system, managed to grant themselves an overwhelming 1,200,000 votes through a malicious proposal. This number far exceeded the approximately 700,000 legitimate votes, effectively handing over the reins of the governance system to the attacker. The incident was first spotted when an unusual transaction was detected on the Ethereum blockchain.

The attacker exploited a vulnerability in the governance system related to a selfdestruct() call. This function, when used with CREATE2, allows arbitrary code to be executed in the governance memory. The attacker used this loophole to artificially inflate their TORN token balance, effectively giving themselves a majority of the votes. The attack was executed through a malicious proposal which unfortunately was accepted. The proposal granted the attacker an overwhelming number of votes, effectively handing themselves control of the governance system. Also, we recommend reading the Full Governance Attack Description from participants of the Tornado community.

Pre-Attack anomalies: Some warning signs

  1. Curiously, but the community itself detected one of the exploit preparation steps, but failed to recognize it as a threat of a full-blown hack.
  2. After the attack, while parsing the hacker’s transactions, strange null approvals on mapping accumulatedRewards through a call to lockWithApproval() were detected. Also, you can analyze all (approximate) attacker’s contracts at Learn-evm-attacks sandbox.

Examination results and consequences: The importance of comprehensive auditing

  • Our examination led us to suspect that the null approvals may have been the initial plan of the hacker to make gas prices for subsequent transactions lower. Given the suspicion, it appears to be a distraction tactic to make everyone lost in irrelevant transactions.
  • The governance contract update against metamorphic attacks looks decent enough, and it would work if all proposals were scrutinized carefully. Generally speaking, there was no protection either at the level of UICS UI, or at the level of the Governance contract, or at the level of verification of the proposals themselves. It is likely that proposal audits could have prevented the hack, but this question is rarely raised in any DAO.

In addition:

We are currently diving deeper into the lockWithApproval() calls with zero amounts.

This call essentially calculates the staked amount for the address and stores it in the accumulatedRewards mapping. Later, the accumulatedRewards can be withdrawn using the getReward() call.

Our assumptions about the hacker’s intentions are as follows:

  1. Initially, they may have wanted to quietly withdraw tokens without causing a drastic drop in TORN’s price. Hence, before the attack, they “prepared” their 100 addresses by calling lockWithApproval() with a zero amount. This sets the accumulatedRewardRateOnLastUpdate map’s value for each address to the current rate, making the stake appear normal and unremarkable by calling lockWithApproval with a zero amount. This sets the accumulatedRewardRateOnLastUpdate.
  2. Perhaps their original plan to withdraw funds discretely failed, so they rapidly took everything out of the governance vault. At this point, the addBurnRewards() method in the staking contract tipped the scales, and all stakers started accruing massive stakes. The hacker prepared their remaining 53 addresses by storing this massive stake in the accumulatedRewards mapping for each address in this transaction.

The nature of Metamorphic contracts

The SELFDESTRUCT opcode problem

In Ethereum, the SELFDESTRUCT opcode is a function that allows a contract to delete itself and send its balance to another address. While this function can be useful in certain cases, it can also be exploited if not handled carefully.

The SELFDESTRUCT function is part of a group of functions known as “metamorphic contracts’’. These are contracts that can change their own code. While this can be useful for upgrading contracts, at the same time it introduces security risks if not properly audited and controlled.

Several Ethereum Improvement Proposals (EIPs) have been made to address the issues related to the SELFDESTRUCT opcode and metamorphic contracts. These include:

  • EIP-2936: This proposal aims to mitigate the risks associated with the SELFDESTRUCT opcode by introducing a new opcode that will prevent contracts from being destructed.
  • EIP-4758: This EIP proposes a method to improve the security of metamorphic contracts by introducing a new opcode that would allow contracts to change their own code without the need for SELFDESTRUCT.
  • EIP-4760: This proposal seeks to make the SELFDESTRUCT opcode safer by introducing a delay before the contract is actually deleted.
  • EIP-6046: This EIP proposes a new opcode that would allow contracts to change their own code without the need for SELFDESTRUCT, making metamorphic contracts safer.
  • EIP-6049: This proposal aims to make the SELFDESTRUCT opcode safer by introducing a delay before the contract is actually deleted.
  • EIP-6780: This EIP suggests removing the SELFDESTRUCT opcode altogether, arguing that it introduces more risks than benefits.

These proposals highlight the ongoing efforts in the Ethereum community to improve the security of smart contracts and DAOs. They also emphasize the importance of comprehensive auditing of not just the code of smart contracts, but also the proposals that govern their operation.

Regarding the SELFDESTRUCT opcode, while it’s true that it has been associated with security risks, it’s also a part of core Ethereum’s functionality, and removing it completely could have implications for existing contracts that rely on it. This is likely a part of the ongoing discussion in the Ethereum community.

How SELFDESTRUCT is used in hacking

In an example of the Tornado Cash Governance hack, the attacker used SELFDESTRUCT in conjunction with the CREATE and CREATE2 opcodes to execute malicious code in the governance memory.

The scheme of malicious contracts deployment looks really elegant:

The key point is that the usage of the Deployer contract allows resetting the Nonce and redeploying code to the same address (See also Rekt.News TL;DR).

What are the possible solutions?

To reduce the risk of approving a malicious Proposal, the developers can introduce a visual representation of the Proposal commit hash that is being voted on at UX/UI level. This would give voters more information about what technical changes will be implemented, and in what order. In turn, this will allow more participants to locally test and verify the Proposal.

The community may occasionally turn to professional audit teams and third-party researchers to review and validate the security of the Proposals in question, at least in those cases when there are doubts. As a best practice, each Proposal should be validated in advance before being put to a vote.

The problem of inactive DAO

Proposals generation and validation algorithm

The decision-making mechanism in a DAO relies on community members putting up a proposal for discussion, which must then be voted for or against by Governance token holders. The first condition for the validity of the vote is that a quorum — a predetermined minimum number of tokens that must be involved in the vote — is reached.

Proposals are also limited in the time in which governance members can vote for or against. Accordingly, if board members are low-key, do not participate in votes, and fail to properly check what they are voting for, this opens a window of opportunity to skillful and non-obvious hacks.

The Tornado Governance case

In the case of the Tornado Governance, several factors combined:

  • After the sanctions on the protocol, the development team had to deal with a bunch of legal and institutional issues that fell on their shoulders out of the blue, making it impossible to validate each proposal so actively.
  • The attacker presented proposal #20 as a solution to routine protocol problems similar to the previously adopted proposal #16, thereby putting inattentive voters at ease.
  • The hacker kept the code of the previously accepted proposal #16 practically unchanged. The only small difference was the presence of the emergencyStop() function, which had selfdestruct() in it. But it was exactly this difference that led to such tragic consequences.
  • Voting members did not bother to thoroughly check the proposal for security, taking the word of a couple of programmers who also were not careful and serious enough about this aspect.

Defense strategies: Preventing DAO hacks

DAO attack vectors

Moreover, coin voting is susceptible to a variety of attacks, including vote buying, vote lending, and whale collusion, while also being exposed to complex Game-Theoretic Attacks, such as, for example, Beanstalk hack and Dharma Proposal hack of Uniswap. And these are only non-technical problems. There are also purely technical bugs that a programmer may introduce to the code due to distracted attention or insufficient knowledge of how blockchain works.

Let’s explain the most common DAO Voting Vulnerabilities:

  • Flash Loan Attacks: These can occur when a hacker can vote and execute a proposal in the same block. To prevent this, DAOs can use mechanisms that calculate the user’s balance one block before the proposal was created, making flash loan attacks impossible. For more details we recommend to analyze MakerDAO flash loan hack.
  • Incorrect Re-vote: This vulnerability arises if a contract allows a user to re-vote on a proposal, but it subtracts the user’s old vote incorrectly. This can be prevented by correctly adding/subtracting the previous voting power during a re-vote.
  • Missing Proposal Validation: If a proposal’s properties are not fully validated, a hacker may have social engineering opportunities to create a destructive proposal that would look benign. DAOs can counter this by implementing robust proposal validation mechanisms. For more details see how Compound applied malicious Proposal and lost more than $80.M link 1 — link 2.
  • No Transfer Validation: A token locking mechanism should check the return value of an approved transferFrom() call and other transfer-like methods. This can be avoided by ensuring that the token locking mechanism checks the return values of such calls.
  • Small Voting Window: Users and veto-holders who are negatively inclined to some proposals may not have the needed time to react. To mitigate this risk, DAOs can set up a reasonable voting period to allow all participants to vote.
  • Double Vote: This occurs when a hacker votes for a proposal twice with the same tokens. For example, vote-transfer-vote or vote-delegation-vote schemes can be used in attack. It can be counteracted by implementing mechanisms that prevent users from voting twice on the same proposal with the same tokens.
  • Double Execution: This happens when the execute() method can be called twice in the same block. In order to avoid it, one can use the Checks-Effects-Interactions pattern, which makes execution methods invulnerable to re-entrancy.

DAO defense practices

In the face of the vulnerabilities that DAOs may encounter, it’s crucial to have robust defense strategies in place. These strategies should address not only technical, but also governance-related challenges. Here are some protection strategies that can be employed to protect DAOs from potential attacks:

  • Multi-Signature Wallets: Using multi-signature wallets can add an extra layer of security to a DAO. These wallets require multiple signatories to approve an action, making it harder for a single attacker to take control.
  • Time Locks: Implementing time locks for proposals can prevent flash loan attacks. It means that there will be a delay between the time a proposal is made and the time it can be executed, giving the community time to react and potentially cancel a malicious proposal.
  • Quorum Requirements: Setting a quorum requirement for proposals can block a small group of individuals from pushing proposals forward. For a vote to be valid, a certain percentage of all token holders must participate in this vote.
  • Delegation: Delegation allows token holders to delegate their voting power to a trusted party. This can help to mitigate the problem of inactive token holders and ensure that more votes are cast in each decision.
  • Voting Periods: Having longer voting periods can ensure that all members of the DAO have a chance to participate in the decision-making process, regardless of their time zone or schedule.
  • Code Audits: Regularly auditing the code of the DAO can help to identify and fix potential vulnerabilities. This includes both internal audits and third-party audits.
  • Bug Bounties: Offering bug bounties can incentivize white-hat hackers to find and report vulnerabilities in the DAO’s code.
  • Transparent Governance: Maintaining transparency in all governance processes can help to build trust within the community and deter malicious actors.

Auditing Governance Proposals

Due to the rather high number of hacking cases with malicious proposals involved, our team found it quite interesting to start conducting full-scale audits for them. We believe that a high-quality audit of proposal code will significantly improve the security of Governance protocol and can prevent possible attacks in time.

Afterword: The Path Forward

In conclusion, we just want to once again emphasize that even minor changes in the code base, sometimes as small as a single line, can lead to a complete loss of control over the protocol and the money flow. Be careful and don’t disregard security audits.

Tornado Governance update

There are good news! After the execution of Proposal #22, all the attacker’s EOA balances were reset to zero, the Governance regained control of the protocol.

About Oxorio

Oxorio is a young but rapidly growing audit and consulting company in the field of the blockchain industry, providing consulting and security audits for organizations from all over the world. Oxorio has participated in multiple blockchain projects during which smart contract systems were designed and deployed by the company.

Oxorio is the creator, maintainer, and major contributor of several blockchain projects and employs more than 5 blockchain specialists to analyze and develop smart contracts.

🗃️ References

[1] — Mixbytes | _article “DAO voting vulnerabilities”;

[2] — _Mixbytes | article “Metamorphic smart contracts: Is EVM Code Truly Immutable?”;

[3] — _“The Promise and the Peril of Metamorphic Contracts”;

[4] — Tornado Governance forum | thread “Attacker transaction history”.

Case Study



Have a question?

Have a question?

Stay Connected with OXORIO

We're here to help and guide you through any inquiries you might have about blockchain security and audits.