Many of the hacks that befall web3 projects would be preventable with more emphasis on smart contract security.
Commonly, attackers find and exploit multiple deficiencies across the software development supply chain – the series of steps that go into releasing new code into the world, from design to deployment and upkeep. If proper protocols and best practices were more readily available, we believe far fewer security incidents would occur.
The purpose of this post is to outline the core security fundamentals that web3 builders, developers, and security teams must consider when designing, developing, and maintaining a secure smart contract system. The framework presented below discusses eight core categories of security considerations – from threat-modeling to emergency response preparation – that should be implemented throughout the software development lifecycle.
Before jumping into the smart contract security considerations, it’s important to understand the development phases for a secure software supply chain, which can be described in the following five phases:
- A) Design: Developers describe the system’s desired features and operations, including important benchmarks and invariant properties.
- B) Develop: Developers write the system’s code.
- C) Test & Review: Developers bring all modules together in a testing environment and evaluate them for correctness, scale, and other factors.
- D) Deploy: Developers put the system into production.
- E) Maintain: Developers assess and modify the system to ensure that it is performing its intended functions.
With this basic lifecycle foundation, let’s now drill down into the smart contract security considerations affecting each step. The figure below maps the considerations to their relevant development phases. Note some steps in the supply chain have multiple security considerations:
But the software development lifecycle, so linearly laid out above, does not necessarily always follow a linear path: Categories may overlap or extend to additional phases in practice. Steps may be repeated for every release. And some tasks – such as testing and security reviews – may need to be performed throughout.
While the software lifecycle steps and corresponding security considerations depicted above provide a useful basis for promoting smart contract security, we examine them in greater detail below. The key questions to make understanding, applying, and sharing these best practices as simple and concrete as possible are what, why, and how.
Smart contract security considerations for the design phase (A)
#1: Consider threat modeling and security design
- What: It’s important to implement an explicit practice of identifying and prioritizing potential threats to a system from the very beginning of the development lifecycle – smart contract developers should identify any security controls to implement in development as well as any threats that should be checked for in testing, audits, and monitoring. All security assumptions, including an attacker’s expected level of sophistication and economic means, should be clearly defined and articulated in the design phase.
- Why: While it’s tempting for developers to focus solely on the intended uses of a smart contract or protocol, this sole focus can leave them with blind spots that attackers can and will exploit.
- How: Follow known threat modeling practices. If a development team does not have in-house security expertise, then it should engage with security consultants early in the design phase. Adopt an “attacker” mindset when designing the system and assume any individuals, machines, or services can reasonably get compromised.
Security considerations for the development phase (B)
#2: Consider administration and access control
- What: Implement access controls that restrict the ability to call special functions that do administrative tasks – such as upgrading contracts and setting special parameters – to privileged accounts and smart contracts. Follow the “principle of least privilege”: that each actor should only have the minimal amount of access required.
- Why: Maintaining protocols through upgrade and governance processes allows developers to improve the protocol by adding new features, patching security issues, and addressing changing conditions. If the ability to make upgrades is not appropriately controlled, this can constitute a critical security vulnerability.
- How: Set up a multisignature wallet (multisig) or DAO contract that will administer changes on behalf of the community in a transparent manner. Changes should undergo a thorough review process, along with a timelock – intentionally delayed enactment with the ability to cancel – to ensure that they can be verified for correctness and rolled-back in the event of a governance attack. Ensure that privileged keys are stored and accessed securely in self-custodial wallets or secure custodial services.
#3: Consider reusable, battle-tested templates and integrations
- What: Whenever possible, make use of existing smart contract standards (e.g., OpenZeppelin Contracts) and evaluate the security assumptions of protocol integrations that you might need to make with existing protocols.
- Why: Using existing battle-tested, community audited standards and implementations goes a long way in reducing security risks. Assessing the risks of protocol integrations helps you develop security checks to protect against attacks on external components such as oracle manipulation.
- How: Import trusted contract libraries and interfaces that have been audited for security; the whole point of crypto and web3 is open source use, re-use, and composability after all! Be sure to document your contract dependencies and their versions in the codebase and minimize your code footprint where you can; for example, import specific submodules of large projects instead of everything. Understand your exposures so you can monitor for supply chain attacks. Use official interfaces for calling external protocols and be sure to take potential integration risks into account. Monitor updates and security disclosures from contracts you’ve reused.
Security considerations for the test & review phase (C)
#4: Consider testing and documentation
- What: Create clear, comprehensive documentation of the code, and set up a fast, thorough, easy-to-run test suite. Where possible, set up test environments on testnets or through mainnet simulation for deeper experimentation.
- Why: Writing out assumptions for a codebase’s expected behavior helps to ensure that risks in threat models are being addressed, and that users and external auditors understand the development team’s intentions. Creating a test suite for the code helps to prove – or disprove – development assumptions and encourages deeper thinking about threat models. This test suite should include tests of mechanism designs that check the tokenomics of a project under extreme market scenarios, along with unit testing and integration tests.
- How: Implement known testing framework and security checkers – such as Hardhat, Mythril, Slither, Truffle, etc. – that provide different testing techniques, such as fuzzing, property-checking, or even formal verification. Document your code – extensively – using NatSpec comments to specify intended side effects, parameters, and return values. Produce live documentation using documentation generation tools alongside high-level design explanations.
#5: Consider internal reviews and security audits
- What: Dedicate time to finding bugs through both internal and external code reviews.
- Why: Stepping away from feature development to focus on security concerns gives developers time to find potentially obscure issues. External audits can be especially helpful in this, as they can bring outside perspectives and expertise that the development team does not have.
- How: At an appropriate juncture in project development, schedule a feature freeze to allow time for an internal review, followed by an external audit. This should take place prior to any live deployments and upgrades. Check out guides from ConsenSys, Nascent, OpenZeppelin, and Trail of Bits, which provide developers with checklists of considerations – including timing – for anyone preparing for an audit. Be sure also to review deployment transactions to ensure they use the audited code version and have the appropriate parameters, especially when upgrading software.
Security considerations for the deployment (D) & maintenance (E) phases
#6: Consider incentivizing whitehat community engagement
- What: Create programs that encourage community participation in security improvement on open-source codebases. One way to do this is by creating bug bounties. Another way is to encourage the community to develop protocol-monitoring detection bots.
- Why: Development teams can benefit greatly from tapping into a wider pool of knowledge and experience. (Again, also the point of where open source helps in crypto.) Notably, such programs can help generate enthusiasm for a project, essentially turning the community and whitehat hackers into evangelists. They can also help turn would-be attackers into security assets by providing paths for hackers to become defenders.
- How: Use bug bounty platforms (such as Code4rena, HackenProof, Immunefi, or Secureum) to fund bounty systems with severity-based rewards that incentivize skilled hackers to safely disclose vulnerabilities. [Full disclosure, some of the co-authors of this post work for Forta, which has a network which offers a tokenized incentive structure for the decentralized creation of high-quality security-monitoring bots.] Development teams can encourage their protocols’ communities to take advantage of both traditional and web3-native approaches to incentivizing bug bounties, and for the participants to potentially profit by enhancing security in a win/win for all.
#7: Consider real-time monitoring
- What: Implement systems that monitor smart contracts and critical operational components such as oracles and bridges, and report suspicious activity to the development team and community based on known threat models.
- Why: Early detection of issues allows a team to respond to exploits and bugs quickly, potentially stopping or mitigating any damage. This seems obvious but can be overlooked in planning.
- How: Use monitoring platforms or distributed nodes to run bots that monitor smart contract events in real-time. Implement dashboards and alert notifications for development teams and the wider community as needed.
#8: Consider incident and emergency response operations
- What: Make use of tools and processes that enable an immediate response in the event of any security issues.
- Why: Even with the best pre-deployment safeguards, it is still possible for smart contracts and critical components, such as oracles and bridges, to have live issues. Having dedicated personnel, clear processes, and appropriate automations in place ensures that incidents can be investigated quickly – and resolved as swiftly as possible.
- How: Prepare for the worst by planning how to respond to incidents or emergencies and automating response capabilities to the greatest extent possible. This includes assigning responsibilities for investigation and response to capable personnel that can be publicly contacted about security issues via a distributed security mailing list, instructions in the code repository, or by a smart contract registry. Based on the protocol’s threat models, develop a set of processes that could include scenario drills and expected response times for taking emergency actions. Consider integrating automation into incident response: for example, tools can ingest and act upon events from Forta bots.
Security considerations should be an integral part of successful development – not just an afterthought or add-on.
While this framework shares some quick guidance for those building web3 protocols and applications to promote security throughout the development process, no short overview can provide an exhaustive discussion of all aspects of smart contract security. Teams lacking in-house security expertise should reach out to qualified web3 security experts who can assist them in applying the general guidance above to their specific situations. But above all, remember that security is never just a simple matter of ticking boxes in a simple checklist manifesto to manage complexity; as such, it’s always going to be a never-ending, ongoing set of best practices. We’re still at the beginning of establishing these best practices, so now is the time to collaboratively create and share them, at all levels for all developers.
Editor: Robert Hackett @rhhackett
Andy Beal is the ecosystem lead at Forta. Previously, he helped manage EY’s blockchain practice.
Nassim Eddequiouaq is the chief information security officer for a16z crypto. He previously worked at Facebook, Anchorage, and Docker.
Riyaz Faizullabhoy is the chief technology officer for a16z crypto. He previously worked at Facebook, Anchorage, and Docker.
Christian Seifert is a researcher-in-residence at Forta. Previously, he spent 14 years working on web security at Microsoft.
The views expressed here are those of the individual AH Capital Management, L.L.C. (“a16z”) personnel quoted and are not the views of a16z or its affiliates. Certain information contained in here has been obtained from third-party sources, including from portfolio companies of funds managed by a16z. While taken from sources believed to be reliable, a16z has not independently verified such information and makes no representations about the enduring accuracy of the information or its appropriateness for a given situation. In addition, this content may include third-party advertisements; a16z has not reviewed such advertisements and does not endorse any advertising content contained therein.
This content is provided for informational purposes only, and should not be relied upon as legal, business, investment, or tax advice. You should consult your own advisers as to those matters. References to any securities or digital assets are for illustrative purposes only, and do not constitute an investment recommendation or offer to provide investment advisory services. Furthermore, this content is not directed at nor intended for use by any investors or prospective investors, and may not under any circumstances be relied upon when making a decision to invest in any fund managed by a16z. (An offering to invest in an a16z fund will be made only by the private placement memorandum, subscription agreement, and other relevant documentation of any such fund and should be read in their entirety.) Any investments or portfolio companies mentioned, referred to, or described are not representative of all investments in vehicles managed by a16z, and there can be no assurance that the investments will be profitable or that other investments made in the future will have similar characteristics or results. A list of investments made by funds managed by Andreessen Horowitz (excluding investments for which the issuer has not provided permission for a16z to disclose publicly as well as unannounced investments in publicly traded digital assets) is available at https://a16z.com/investments/.
Charts and graphs provided within are for informational purposes solely and should not be relied upon when making any investment decision. Past performance is not indicative of future results. The content speaks only as of the date indicated. Any projections, estimates, forecasts, targets, prospects, and/or opinions expressed in these materials are subject to change without notice and may differ or be contrary to opinions expressed by others. Please see https://a16z.com/disclosures for additional important information.