A critical security vulnerability in Parity multi-sig wallet got triggered on 6th November — paralyzing wallets created after the 20th July.

As you may have read, Parity issued a security advisory today to inform its users and developers about a bug that got “accidentally” triggered which resulted in freezing more than $280M worth of ETH, including $90M belonging to Parity’s Founder & Ethereum former core developer: Gavin Woods.

How long has this bug been around for?

As Dan Guido points out, this new vulnerable contract has been deployed more than 100+ days ago on July 20th, one day after the original multi-sig vulnerability had been exploited and fixed.

The Bug

A user named devops199 claimed he triggered the bug “accidentally” and reported it through a GitHub ticket.

image

The newly deployed contract, 0x863df6bfa4469f3ead0be8f9f2aae51c91a907b4, contains a vulnerability where its owner was uninitialized. Although, the contract is a library it was possible for devops199 to turn it into a regular multi-sig wallet since for Ethereum there is no real distinction between accounts, libraries, and contracts.

The event occurred in two transactions, a first one to take over the library and a second one to kill the library — which was used by all multi-sig wallets created after the 20th of July.

Transaction #1

In the above transaction, the user initialized the owner to himself 0xae7168deb525862f4fee37d987a971b385b96952 of the Parity library using the initWallet() function which is the function that was originally exploited on July 19th. Assigning an owner to the library directly enabled the user to convert the library into a regular multi-sig wallet.

// throw unless the contract is not yet initialized.  
modifier only_uninitialized { if (m_numOwners > 0) throw; _; }  

 // constructor - just pass on the owner array to the multiowned and  
 // the limit to daylimit  
function initWallet(address[] _owners, uint _required, uint _daylimit) only_uninitialized {  
    initDaylimit(_daylimit);  
    initMultiowned(_owners, _required);  
 }

Transaction #2

After initializing himself as owner of the library (now regular multi-sig wallet), the user was able to call the kill() routine which resulted in paralyzing all the wallets that were dependent of this third party library. This affects all the wallets created after 20th July, since they can’t use this library anymore.

// kills the contract sending everything to `to`.  
function kill(address _to) onlymanyowners(sha3(msg.data)) external {  
    suicide(_to);  
 }

Conclusion

Even though the vulnerable smart-contract was open source and deployed months ago, this bug managed to escape code review done by the Parity team.

Since by design smart-contracts themselves can’t be patched easily, this make dependancies on third party libraries very lethal if a mistake happens.

The fact that libraries are global is also arguable, this would be shocking if it was how our daily use Operating Systems would work. Modern O.Ss improved their security over the past 20 years mainly because of all the security mitigations being implemented (NX, KASLR etc.), those mitigations come from the compiler and the O.S. itself. Every time a new class of bug is discovered, hardware and O.S. vendors work on kill the class of bug — hardforking should not be the only solution to problems. Writing virtual machines, and compilers is hard.

We have seen a lot of enthusiasm from a lot of people about blockchain-based smart contracts, and the general assumption from users is that they would be secure. But just like any other piece of software a smart-contract can be vulnerable.

All the recent security issues around smart contracts are challenging more and more the sustainability of storing money on a blockchain-based programmable software layer.

If you want to know more about Ethereum internals and security, I invite you to watch my DEFCON talk of this summer.