As discovered today, the multiple signature wallet smart contract that ships with the Parity client was discovered to have a critical vulnerability, which allowed attackers to instantly take over a wallet and siphon out all of the funds. An estimated $30,000,000 USD was lost to hostile attackers, but the majority of the vulnerable funds were saved by a white hat group who worked to rescue vulnerable wallets before the attackers could access them.

This attack is unique in both how long the bug has remain dormant, and also in how easy it is to actually utilize the exploit. In this post, we break down exactly how the exploit happened, and how it could have been prevented. We also touch on some interesting points that contributed to the long lifespan of the bug before being discovered.

Explanation

Imagine if you could walk into a bank and request that they transfer ownership of a stranger’s account into your name. The bank happily does so, and you withdraw all of the account’s money. This is, in essence, what happened with the Parity multi-sig today.

The fundamental vulnerability in the wallet code was in not properly restricting access to methods. In Solidity, a method that has no modifier is considered public . This means that the method can be accessed from any source, including external transaction calls made to the contract. In the Parity multi-sig, a critical mistake was made in not specifying the modifier for the following method:

function initWallet(address[] _owners, uint _required, uint _daylimit) {

initDaylimit(_daylimit);

initMultiowned(_owners, _required);

}

This method is intended to initialize the wallet using the given array of signers, number required to confirm a transaction, and the limit per day allowed to be moved before requiring a confirmation. Note the lack of a visibility modifier on the function, which defaults it to public . Thus, anybody is allowed to call this function, and can freely set the parameters to whatever they like. To an attacker, they could set the ownership to their own address, and the day limit to be high enough to siphon out all of the funds in a single transaction.

This vulnerability appears another time in the wallet code, but the above method was the primary attack vector used.

Fixing the Issue

The fix for this is extremely simple, and has already been made by the Parity developers. The methods affected must simply be marked as internal , to ensure that no outside party can access the method. Unfortunately, any pre-existing wallet that still exists on the blockchain remains vulnerable to the issue.

The fix is the equivalent of asking the bank not to let anybody (except the bank’s staff) make changes to your account.

Prevention

With this issue, several questions are inevitably raised: how did such a straightforward bug slip its way into a contract this prolific? What assurance and guarantee do we have that something like this won’t happen again?

There are several strategies and changes that could be put into action to ensure oversights like this do not reach the same scale. By far the most effective defense is to ensure that all code is code reviewed and also audited for security flaws and mistakes. No smart contract code should be released for public consumption without first being thoroughly combed through. However, this is limited to the time and experience of those reviewing the contract, and is not a guarantee that every vulnerability will be caught.

Commonly, automated test cases (called unit tests) are used to ensure contract code behaves appropriately and as expected. These tests are extremely valuable, especially in the long term as the code being tested undergoes change and improvement. The test cases provide a fast, automated, and deterministic way to check the same set of conditions each time they are executed. This prevents regressions in the behaviour of the code, and ensures that future changes do not break the code in any way. The weakest part of unit testing is that every test case must be written manually. If a bug exists in some part of the code that does not have an associated test case, then it will never be caught.

There is also the concept of formal verification, in which code is mathematically proven to behave as expected. This is used commonly alongside functional programming languages, whose paradigms make it particularly well suited to being verified in this manner.

Additionally, Solidity could take significant steps towards better security by defaulting methods to be private , instead of public . This means a small oversight such as what happened to Parity will not result in such devastating consequences.

There is no “silver bullet” when it comes to preventing vulnerabilities, but there is significant room to grow. The Ethereum space is rapidly developing and innovating, but great care must be taken to ensure everything is done safely and soundly. We at BlockCAT put security at the forefront of everything we do, and work extremely hard to ensure that any risk involved with our smart contracts is minimized to the smallest possible extent. Recognizing the immense transaction volume that passes through the blockchain on a daily basis makes our mission all the more critical.

If you agree with better security and a safer blockchain for everyone, join our token sale now to help bring accessible, friendly, and safe smart contracts to everyone.

Why This Wasn’t Discovered Earlier

There were several factors that contributed to the longevity of this bug. First is the social issue of taking comfort in a crowd — the Parity multi-sig wallet was extremely common and ubiquitously used. Many major token sales were utilizing the wallet to store their funds. This falls into the fallacy of assuming that popularity equates to security. However, if nobody takes the time to verify the code, then the popularity only serves to multiply the severity of the attack.

Parity also made a crucial error in the way they presented their wallet code. When deploying the multi-sig, the subtitle links to the Solidity code used to facilitate the wallet. However, at one point this link 404'd and didn’t direct to the appropriate contract. This was an issue fixed in a later Parity release.