Introducing Solidify — a tool to automatically detect and classify smart contract security risks
By Peter Kacherginsky, Principal Blockchain Security Engineer
When our blockchain security team started doing a few smart contract security reviews in 2018, we had no idea that we would be doing hundreds of reviews in 2021.
To grow the open financial system, Coinbase is committed to expanding its list of supported cryptocurrencies. Recently, we launched the Asset Hub to streamline our diligence process for new listings. One of the critical factors we consider is smart contract security, especially with regard to Ethereum-based tokens which can vary greatly in technical complexity. Therefore, we created a smart contract security tool called Solidify to help automate, standardize, and scale this process.
Manual smart contract analysis is a time intensive and error prone process. Experienced teams miss occasional vulnerabilities which can lead to significant monetary loss. To keep our customers and Coinbase safe, our token listing process requires security reviews and risk mitigation recommendations for every smart contract. Consider our challenge of figuring out how to do this specialty risk identification and recommendation process at scale. We identified existing smart contract security scanners that are geared toward manual reviews. But these tools do not offer the required safety guarantees and standardized risk scoring for fully automated analysis.
To solve this problem we developed a tool called Solidify (a play on Solidity) to increase the rate of new asset security reviews without lowering our high security standard that Coinbase customers have come to expect for protecting their tokens. Solidify uses a large signature database and a pattern matching engine to reliably detect contract features and their risks, standardize and score smart contract risks, suggest mitigation strategies, and generate detailed reports to help inform our decision on whether or not Coinbase should list the asset. Solidify evaluates security risks of hundreds of smart contracts either fully automatically or through identification of unique functions that require additional manual review.
How Solidify Works
Most smart contract risks come from operations design choices by asset issuers that introduce potentially dangerous functionality (e.g. freezing, upgrading, etc.) or non-standard function implementations that are insufficiently tested (e.g. custom withdrawal logic). On the design side, we observe most asset issuers using standard patterns such as OpenZeppelin’s contracts library to implement features like asset pausing:
contract Pausable is Ownable {
event Pause();
event Unpause();
bool public paused = false;
modifier whenNotPaused() {
require(!paused);
_;
}
modifier whenPaused() {
require(paused);
_;
}
function pause() onlyOwner whenNotPaused public {
paused = true;
Pause();
}
function unpause() onlyOwner whenPaused public {
paused = false;
Unpause();
}
}
Source: openzeppelin-contracts-1.3.0/contracts/lifecycle/Pausable.sol
By using the above pause() functions, the owner of the smart contract can halt all send/receive operations and, in some cases, negatively impact the contract utility. By the presence of the pause library and respective transfer functions which use them, we can reliably classify the contract having a risk of getting paused. Solidify does this by aggregating all known instances and possible variations on the pause() function and automatically checking if the currently analyzed contract has it. Unique signatures are generated using AST (Abstract Syntax Tree) structures to avoid duplicates produced by slight variations in syntax while ensuring grammatical accuracy of what the function actually does.
The above sample AST tree for the pause() function will be processed to generate a unique hash which will be used as a signature to match against other smart contracts:
Below is a sample entry in the signature database generated by Solidify for the pause() function:
{
"Hash":
"05654d81921af71079698aff1b4be500d1405ece9364a05915b738376c0250b5",
"Name": "pause()",
"Mutability": "nonpayable",
"Source": ["signatures/openzeppelin/openzeppelin-contracts-1.10.0/contracts/lifecycle/Pausable.sol:666:90:0",
"signatures/openzeppelin/openzeppelin-contracts-1.11.0/contracts/lifecycle/Pausable.sol:666:90:0",
"signatures/openzeppelin/openzeppelin-contracts-1.9.0/contracts/lifecycle/Pausable.sol:666:90:0"
[.. redacted ..]
],
"Doc": "@dev called by the owner to pause, triggers stopped stater",
"Features": [
"pausing"
]
},
Notice that the same pause() function signature is present across 3 different releases of the OpenZeppelin library and other tokens that included that code verbatim. The above signature also includes a list of features such as “pausing” which allows us to automatically evaluate asset’s risk and suggest mitigations (e.g. robust multi-sig for the owner account). Solidify performs similar signature matching against every single function in an analyzed contract until all functions are either detected or added to our signature database so we never need to analyze the same code twice.
Solidify currently has about 6,000 unique signatures which are used to efficiently match risks against any given smart contract. A manual review which took up to 2 work days in 2018 can be performed in just a few minutes in 2021. Solidify’s capabilities and detection rates are continuously growing as our security engineers add new signatures and record associated risks.
How to Use Solidify
Let’s analyze a sample smart contract to illustrate the signature matching engine in action. Let’s look at ChainLink Token (LINK) and see how secure it is by running Solidify on its smart contract deployed at 0x514910771af9ca656af840dff83e8264ecf986ca:
% ./solidify -a 0x514910771af9ca656af840dff83e8264ecf986ca
2021/05/20 15:16:22 Loaded 5777 function signatures
2021/05/20 15:16:22 Processing 0x514910771af9ca656af840dff83e8264ecf986ca
2021/05/20 15:16:23 Loading signatures from: contracts/LINK_0x514910771af9ca656af840dff83e8264ecf986ca/LinkToken.sol
2021/05/20 15:16:23 Generating AST for contracts/LINK_0x514910771af9ca656af840dff83e8264ecf986ca/LinkToken.sol
2021/05/20 15:16:24 Installing solidity version 0.4.21
2021/05/20 15:16:28 Set solc version to 0.4.21
2021/05/20 15:16:29 Detected 19 signatures
2021/05/20 15:16:29 Storing report in reports/LINK_0x514910771af9ca656af840dff83e8264ecf986ca/LINK.yml
2021/05/20 15:16:29 Storing report in reports/LINK_0x514910771af9ca656af840dff83e8264ecf986ca/ChainLink Token (LINK) Security Memo.md
It took only a few seconds for Solidify to automatically download the contract source code, generate ASTs using an appropriate Solidity version, detect and match 19 unique function signatures. Below is a snippet of the Markdown report produced by the tool:
ERC-20 Security Assessment: ChainLink Token (LINK)
Auditor: Peter Kacherginsky
Solidify version: 1.2.3
Contract Source: 0x514910771af9ca656af840dff83e8264ecf986ca
Executive Summary
Date: 2021–05–20
Residual Security Risk Score: 2
Inherent Security Risk Score: 2
Risk Score: 2
Risk Description: External address call
Risk Score: 1
Risk Description: Use of assembly instructions
** Asset risks are calculated on the scale of 1–5 with 5 being the most severe.
No mitigations are necessary for this asset.
Risk Details
ChainLink Token has the following risks:
2 | External address call
The contract may invoke another function on a different smart contract in order to trigger functionality not defined within the contract itself
External address calls increase complexity and risk of the smart contracts. External calls are a prerequisite to re-entrantrancy vulnerabilities.
The following functions triggered this risk:
- contractFallback(address,uint256,bytes memory)
- transferAndCall(address,uint256,bytes memory)
- transferAndCall(address,uint256,bytes memory)
1 | Use of assembly instructions
Assembly instructions use low level interface to directly manipulate the Ethereum Virtual Machine (EVM) as opposed to using the high level Solidity language. For example, inline assembly can make low level calls to other contracts, manipulate storage slots directly, and circumvent developer protections offered by higher level languages.
The use of assembly instructions increases complexity and obfuscates functionality of the smart contract while circumventing some of the inherent compiler protections.
The following functions triggered this risk:
- isContract(address)
Mitigation Details
Implementation of the following risk mitigations drive the residual security risk score: N/A
Monitoring
Slack Monitoring: N/A
Slack and Pagerduty Monitoring: N/A
Matching Function Signatures
062afb9e84bbfded288268dcd3860be4fac7576697e563970dbfedd29dd9f5ff — add(uint256,uint256)
0f5d6c18af8bfe45551aea6c08ee36f2388d40721a399a99210754fb5b5d4fcc — isContract(address)
27711ded0a7898d7ac3feca9c539c7660909efcc5bf12c8e8b8612d522be6ac4 — contractFallback(address,uint256,bytes memory)
2d299e0f7d2ea990e5ca714c04fbac5ae68615d9404bf447f42234f28891fcd5 — transferFrom(address,address,uint256)
3ee09ec574744840001f024d57db0a57f4986733e71f8355bf8cd7af08e03ef4 — transferAndCall(address,uint256,bytes memory)
504201695c6fb08bebd3aaa9ccc252afd104cedddc5a5db8785ff1ec93e3255d -
[.. REDACTED ..]
Matching Function Sources:
signatures/openzeppelin/openzeppelin-contracts-1.1.0/contracts/token/BasicToken.sol
signatures/openzeppelin/openzeppelin-contracts-1.1.0/contracts/token/StandardToken.sol
signatures/openzeppelin/openzeppelin-contracts-1.10.0/contracts/math/SafeMath.sol
signatures/openzeppelin/openzeppelin-contracts-1.11.0/contracts/math/SafeMath.sol
signatures/openzeppelin/openzeppelin-contracts-1.3.0/contracts/math/SafeMath.sol
[.. REDACTED ..]
Most of the contract was taken from standard OpenZeppelin libraries or other known smart contracts which makes the function matching easy. There were only two informational findings related to the use of custom assembly code and making external function calls; however, those do not pose a security risk on their own. Based on the output above, the token would be rated with a risk score of (2) which is considered low risk from a security perspective.
Limitations
Solidify is purpose built to address our need to quickly and securely review ERC-20 and similar tokens. Having standardized token interfaces and a relatively limited functionality necessary to manage accounts is great for building signature databases which match a large percentage of contracts out there. But more complex assets such as AMMs and other DeFi applications require additional manual analysis because of the large percentage of custom code. However, Solidify is still beneficial for these applications when analyzing DeFi clones or for eliminating standard libraries from the manual review scope so analysts can focus on the custom logic.
Although Solidify is currently limited to Ethereum blockchain and Solidity, there are plans to expand the tool to other EVM-based platforms and support additional languages like Vyper.
Since all data in Solidify is manually populated by analysts there also exists a risk where we miss or misclassify features for a signature resulting in an incorrect assessment. We are concerned about deployed contracts trying to hide backdoors through malicious constructors, code obfuscation, exploiting the tool itself, and other techniques. Additional controls are built internally to validate signatures, detect anomalies and malicious behavior.
Future Development
We plan to open source Solidify later this year. In the meantime, additional development is focused on:
- Improving accuracy of signature generation and detection logic
- Integrating formal verification techniques to reduce the need for manual analysis
Conclusion
In this blog we have shared a novel tool and techniques used to automatically detect and classify smart contract risks. Solidify is a powerful and highly configurable tool that can be used by smart contract auditors, asset issuers, and other exchanges to help make digital asset ecosystems more secure. As the cryptoeconomy grows, tools like Solidify will become increasingly vital. Read about the Top 10 Smart Contract Security Risks to learn more about risks that Solidify helps classify.
If you are interested in securing the future of finance, Coinbase is hiring.
Introducing Solidify — a tool to automatically detect and classify smart contract security risks was originally published in The Coinbase Blog on Medium, where people are continuing the conversation by highlighting and responding to this story.