This blog entry offers an update on our discoveries following the detection of the storage corruption issue last week. In essence, the bug was considerably less critical than we initially presumed. The limited number of impacted contracts we identified is either solely exploitable by the owner or the exploitation can merely lead to disruptions in the user interface without affecting the actual contract logic. All exploitable contracts/dapps we examined can be rectified without needing to upgrade the contract itself. Nonetheless, please still verify your contracts to ensure safety.
After identifying the storage corruption flaw in the Solidity compiler and recognizing that it may have significant implications on already-deployed contracts that cannot be modified, we commenced a thorough analysis of the prevalence of the bug and how to address exploitable contracts.
We concentrated on contracts with source code available on etherscan since important or widely-used smart contracts typically have their source code published there to gain trust from their users, who can then authenticate the compilation. Moreover, when the source code is inaccessible, it significantly hinders an attacker’s ability to discover a viable exploit. Lastly, contracts that are used privately (and thus do not necessitate public source code) typically verify that they are called from a specific address, preventing an attacker from writing to their storage.
To automate the process of examining all contracts on etherscan, we developed a modified version of the Solidity compiler capable of automatically detecting the conditions that trigger the bug. This method has already decreased the number of potentially vulnerable contracts to 167. We subsequently manually inspected those contracts for potential storage corruption that could expose them to attacks.
It appears that only ten contracts were vulnerable, enabling us to reach out to most of the contract owners/developers. Seven out of ten of these contracts are only exploitable by the owner in that they have the ability to alter certain parameters beyond their authorized range or to unlock a previously locked contract. One contract can be exploited by unauthorized users but contains other major design flaws. The remaining two contracts identified as exploitable by unprivileged users either offered no benefits if exploited or solely impacted the user interface.
What explains the limited number of exploitable contracts?
Initially, let us clarify what we refer to as “exploitable”:
The storage corruption bug is deemed exploitable if it can be utilized to amend a variable in storage in a manner that would not be feasible without the bug, and this alteration has implications for the behavior and usage of the smart contract. For instance, we do not classify a contract as exploitable under the following circumstances:
- The same account could overwrite the variable under the same condition of the contract through standard means.
- Overwriting can only occur at the time of creation (notably, we did not verify if overwriting took place during that time).
- Overwriting is only activated in improbable scenarios where the contract logic was flawed anyway (for example, a 32-bit counter incrementing once per block results in an overflow).
- Variables can be overwritten that are unused within the smart contract and appear non-essential, yet may be part of the public interface.
What accounts for this critical bug being exploitable in so few instances?
It is a combination of several factors that collectively multiply and significantly decrease the likelihood of exploitability.
- As small types only offer an advantage in exceedingly rare cases, they are infrequently employed.
- Small types need to be adjacent in storage—a solitary large type intervening halts the triggering of the bug.
- State variables are commonly instantiated sequentially, removing the corruption after the second assignment.
- The combination of “address” and “bool” is the most prevalent among the remaining cases, but here, the address variable is often an “owner” assigned from msg.sender and thus not exploitable. Even if the owner can be modified, the flag is frequently a flag that can still be set by the owner through other mechanisms.
How to address affected contracts
The vast majority of the exploitable contracts can only be exploited by the contract owner, administrator, or developer, particularly through a singular function that permits the owner to be altered. This exploitation allows for a further escalation of privileges for the owner. To avert the owner from capitalizing on this exploit, a proxy contract can be established between the owner and the affected contract. This proxy contract relays calls from the owner, while prohibiting the calling of the exploitable functions. If it remains essential to invoke the exploitable functions, the proxy contract can obstruct malicious data from being forwarded to the contract.
If you have particular inquiries or concerns regarding your contracts, please reach out to us on gitter.
A FRIENDLY AND SIGNIFICANT NOTE FROM LEGAL
The assertions in this entry are suggestions to tackle the storage corruption bug in the Solidity compiler. As you are aware, we are operating within an emergent and evolving technical domain. The same aspects that render this endeavor thrilling—the innovation, the effects, the increasing comprehension of how contracts operate—are the very ones that incur risks. Should you opt to implement the recommendations in this entry and continue to engage, ensure that you grasp how it influences your specific contract and acknowledge that there are risks involved. By deciding to adopt these recommendations, you alone accept the risks of the consequences.

