├── .github └── workflows │ └── ci.yml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── docs ├── AMM.md ├── LSDs.md ├── commons-erc-tokens.md ├── compound-fork.md ├── cryptography.md ├── index.md ├── layer2.md ├── oracle.md └── proxies.md ├── mkdocs.yml └── other-checklists.md /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | on: 3 | push: 4 | branches: 5 | - main 6 | permissions: 7 | contents: write 8 | jobs: 9 | deploy: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v3 13 | - uses: actions/setup-python@v4 14 | with: 15 | python-version: 3.x 16 | - run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV 17 | - uses: actions/cache@v3 18 | with: 19 | key: mkdocs-material-${{ env.cache_id }} 20 | path: .cache 21 | restore-keys: | 22 | mkdocs-material- 23 | - run: pip install mkdocs-material 24 | - run: mkdocs gh-deploy --force 25 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## Building locally 4 | 5 | To build a new version of the documentation, first install 6 | the requirements with `pip3 install -r requirements.txt`. 7 | Then change directories (or `cd`) to the `docs/` directory 8 | and run `make clean html`. 9 | Any build warnings or errors will be displayed in your terminal, 10 | and the new documentation will then be available in the `docs/build/html/` directory. 11 | You may also find the 12 | [Sphinx documentation style guide](https://documentation-style-guide-sphinx.readthedocs.io/en/latest/style-guide.html) 13 | useful when editing reStructuredText (reST) if you normally use Markdown. 14 | 15 | ## Guidelines 16 | 17 | When possible, avoid links to websites that are affiliated with 18 | specific security groups or companies. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # About 2 | 3 | The open source knowledge repository for common smart contract bugs. 4 | 5 | The goal is to make a comprehensive checklist of common smart contract errors that can be used in many different contexts. This list intends to make it clearer what is an incorrect and correct pattern looks like to make it easier for anyone to better understand these common issues. 6 | 7 | Is something missing? Review the [contributing guidelines](./CONTRIBUTING.md) and open a PR! 8 | 9 | ## How to run locally 10 | 11 | This project is [built with MkDocs](https://squidfunk.github.io/mkdocs-material/). To run the docs locally, install the Python `mkdocs-material` package with `pip install mkdocs-material` or `pip3 install mkdocs-material`. After the package is installed, navigate to the top level directory of this project and run `mkdocs serve`. 12 | 13 | ## Seriously, why another security checklist?! 14 | 15 | This checklist of security issues in smart contracts aims to differentiate itself in a few ways: 16 | 17 | 1. Seek community contributions rather than attempting a solo effort 18 | 2. Give an explanation about what differentiates a correct implementation from an incorrect implementation, making it easier for anyone (security novices included) to avoid common errors 19 | 3. Link to additional information related to each vulnerability 20 | 4. Provide a nicer layout rendering than a markdown file -------------------------------------------------------------------------------- /docs/AMM.md: -------------------------------------------------------------------------------- 1 | # AMM (Automated Market Maker) 2 | 3 | AMMs allow for swapping between different tokens. Different AMMs have different designs and can involve different risks during integration. 4 | 5 | Other resources: 6 | 7 | - None currently 8 | 9 | ## 1. Is there a user defined slippage value when a swap happens? 10 | 11 | **Incorrect** 12 | 13 | No slippage protection during swaps, or the slippage amount is not user defined. Even if a slippage check exists, the implementation should be examined carefully. 14 | 15 | **Correct** 16 | 17 | The slippage amount is user defined, similar to the `amountOutMin` argument in [the swapExactTokensForTokens function of UniswapV2Router02.sol](https://github.com/Uniswap/v2-periphery/blob/0335e8f7e1bd1e8d8329fd300aea2ef2f36dd19f/contracts/UniswapV2Router02.sol#LL226C14-L226C26). 18 | 19 | **Explanation** 20 | 21 | Slippage is a side-effect of how AMMs operate, meaning slippage is always present in a swap. If there is no slippage protection and the swap can proceed at any price, the swap can be sandwiched or arbitraged by MEV bots, resulting in the user receiving fewer tokens than expected. If there is slippage protection that is hardcoded by the protocol, the swap may revert when the market volatility is high or liquidity is low, resulting in a temporary denial of service for the user who is unable to perform the swap. 22 | 23 | **Links** 24 | 25 | - Code4rena has many findings [related to missing or inadequate slippage settings](https://github.com/search?q=org%3Acode-423n4+slippage&type=issues), including [this one](https://github.com/code-423n4/2022-01-notional-findings/issues/181) and [this one](https://github.com/code-423n4/2022-06-badger-findings/issues/155). 26 | 27 | ## 2. If a single-sided deposit into a multi-token pool is allowed, does the protocol calculate the token swap amount properly? 28 | 29 | **Incorrect** 30 | 31 | No, the protocol naively swaps half the tokens received from the user and then deposits the tokens into the same pool that was used for the swapping process. 32 | 33 | **Correct** 34 | 35 | Yes, the protocol performs the proper math to prevent leftover dust or returns any leftover dust to the user after the deposit process. 36 | 37 | **Explanation** 38 | 39 | If a protocol takes the naive approach of swapping half of the token, this first swap will change the pool balances and exchange rate between the tokens in the pool. It is important to account for the impact of this swap when calculating the amount of tokens that should be swapped for a dust-free deposit into the liquidity pool. The precise math to allow a one-sided deposit into a Uniswap-like pool is [detailed by Alpha Finance](https://blog.alphaventuredao.io/onesideduniswap/). 40 | 41 | **Links** 42 | 43 | - [Alpha Finance single token deposit derivation](https://blog.alphaventuredao.io/onesideduniswap/) 44 | - [One-sided swap finding](https://reports.yaudit.dev/reports/05-2022-OpenMEVRouter/#1-high---the-swap-and-stake-mechanisms-in-openmevzapper-leave-funds-in-the-contract-jackson) -------------------------------------------------------------------------------- /docs/LSDs.md: -------------------------------------------------------------------------------- 1 | # LSDs (Liquid Staking Derivatives) 2 | 3 | LSDs have become a popular way of earning interest on Proof of Stake (PoS) native token staking without locking up the staked tokens. A LSD protocol issues a new liquid token in return for staking the native tokens, which allows users to use their new token in other dApps. 4 | 5 | Other resources: 6 | 7 | - [Decurity LSD checklist](https://blog.decurity.io/typical-vulnerabilities-in-lsd-protocols-e52ffe4ee175) 8 | - [Sigma Prime LSD checklist](https://blog.sigmaprime.io/liquid-restaking.html) 9 | 10 | ## 1. Are withdraw credentials securely handled to prevent a malicious node operator from frontrunning withdrawals with their own credentials? 11 | 12 | **Incorrect** 13 | 14 | No 15 | 16 | **Correct** 17 | 18 | Yes 19 | 20 | **Explanation** 21 | 22 | The process of setting `withdrawal_credentials`, a variable used in the beacon chain withdrawal process, is a key part in determining who receives the ETH upon withdrawal. The `withdrawal_credentials` value must match the key of a depositor. But if a malicious party frontruns a valid deposit from the staking pool with their own deposit of 32 ETH, the withdraw request can include the malicious party's own `withdrawal_credentials` and the malicious party will receive the ETH from the staking pool. This is made possible by the fact that the beacon chain deposit and withdrawal process allows multiple `withdrawal_credentials` based on the addresses of depositors. 23 | 24 | **Links** 25 | 26 | - [Lido and Rocketpool frontrunning bounty writeup](https://medium.com/immunefi/rocketpool-lido-frontrunning-bug-fix-postmortem-e701f26d7971) 27 | - [Tranchess frontrunning bounty writeup](https://tranchess.medium.com/recap-deposit-front-run-vulnerability-mitigation-cfc66ef8c50d) 28 | -------------------------------------------------------------------------------- /docs/commons-erc-tokens.md: -------------------------------------------------------------------------------- 1 | # Common ERC Tokens (ERC20, ERC4626) 2 | 3 | ERC20 and other token standards, the different implementations of this standard do not all play nicely together. In addition, some ERC20 tokens do not follow the standard exactly. 4 | 5 | Other resources: 6 | 7 | - https://ercx.runtimeverification.com/ 8 | 9 | ## 1. Are incompatible versions of this ERC considered? 10 | 11 | **Incorrect** 12 | 13 | No 14 | 15 | **Correct** 16 | 17 | Yes 18 | 19 | **Explanation** 20 | 21 | This is an extremely broad category, but it is hard to enumerate every possible issue related to incompatibility. The best approach is to review the corresponding link below outlining unexpected behavior for each token standard. 22 | 23 | **Links** 24 | 25 | - [Unexpected or non-compliant ERC20 behavior](https://github.com/d-xo/weird-erc20) 26 | - [Unexpected or non-compliant ERC4626 behavior](https://banteg.mirror.xyz/xMsPLpgsv88NFspah0v1SyJHBk0Yp3vSyzCSznr6ZaM) 27 | 28 | ## 2. Are any newly created ERC tokens compliant with the standard? 29 | 30 | **Incorrect** 31 | 32 | No 33 | 34 | **Correct** 35 | 36 | Yes 37 | 38 | **Explanation** 39 | 40 | Every ERC standard contains detailed information about what the contract code must do to remain compliant with the standard. If the contract is importing an ERC implementation from a well-known library, such a OpenZeppelin, there is less likelihood of unusual implementation details when compared to a fully custom ERC implementation. 41 | 42 | **Links** 43 | 44 | - [Slither ERC conformance check for ERC20, ERC4626, and many other token standards](https://github.com/crytic/slither/wiki/ERC-Conformance) 45 | 46 | ## 3. If tokens with OpenZeppelin and solmate ERC imports involved, are incompatibilities considered? 47 | 48 | **Incorrect** 49 | 50 | No 51 | 52 | **Correct** 53 | 54 | Yes, the known compatibility issues have been considered 55 | 56 | **Explanation** 57 | 58 | Solmate's gas optimizations have led to some differences compared to tokens importing OpenZeppelin ERC libraries. Examples of this are linked to below. 59 | 60 | **Links** 61 | 62 | - [IERC20 incompatibility between OZ and solmate](https://github.com/transmissions11/solmate/issues/307) 63 | - [`safeTransfer()` reverts on flashloan for certain tokens in solmate](https://github.com/transmissions11/solmate/issues/346) 64 | - [Missing maxwithdraw check in solmate](https://github.com/transmissions11/solmate/issues/362) 65 | - [`totalAssets()` implementation inconsistency in solmate](https://github.com/transmissions11/solmate/issues/348) 66 | 67 | ## 4. If solmate is used, is there an existence check before any safeTransfer? 68 | 69 | **Incorrect** 70 | 71 | No, and the lack of this check may cause problems 72 | 73 | **Correct** 74 | 75 | Yes 76 | 77 | **Explanation** 78 | 79 | Solmate delegates the responsibility of checking that a token has code to the caller, as stated in the [SafeTransferLib NatSpec](https://github.com/transmissions11/solmate/blob/fadb2e2778adbf01c80275bfb99e5c14969d964b/src/utils/SafeTransferLib.sol#L9). 80 | 81 | **Links** 82 | 83 | - Past Code4rena issues ([1](https://github.com/code-423n4/2022-08-olympus-findings/issues/117) and [2](https://github.com/code-423n4/2023-01-astaria-findings/issues/158)) 84 | -------------------------------------------------------------------------------- /docs/compound-fork.md: -------------------------------------------------------------------------------- 1 | # Compound Finance v2 Forks 2 | 3 | Compound Finance is a popular lending protocol that has been forked many times. Despite this popularity, there have been many hacks of Compound Forks due to common pitfalls. 4 | 5 | Other resources: 6 | 7 | - [List of Compound Finance fork hacks](https://github.com/YAcademy-Residents/defi-fork-bugs#compound) 8 | 9 | ## 1. What is the process for adding new tokens? 10 | 11 | **Incorrect** 12 | 13 | No checks in place to prevent the addition of a ERC777 token 14 | 15 | **Correct** 16 | 17 | Validate that any token that will be added to the protocol has sufficient liquidity, a secure price oracle, is a standard ERC20 token without any callback hooks 18 | 19 | **Explanation** 20 | 21 | The Compound Finance codebase is [vulnerable to reentrancy](https://www.comp.xyz/t/reentrancy-protection-currently-broken/2573). This means that without a process to review new token markets (for example, [this OpenZeppelin checklist](https://github.com/OpenZeppelin/compound-assets-listing)), a token that risks a reentrancy attack or bad debt may be added 22 | 23 | **Links** 24 | 25 | - [CREAM hack with AMP token](https://medium.com/cream-finance/c-r-e-a-m-finance-post-mortem-amp-exploit-6ceb20a630c5) 26 | - [OpenZeppelin asset listing checklist](https://github.com/OpenZeppelin/compound-assets-listing) 27 | 28 | ## 2. What oracle is used for price data? 29 | 30 | **Incorrect** 31 | 32 | Spot price of a Uniswap pool or any price data that can be manipulated with a flashloan 33 | 34 | **Correct** 35 | 36 | A decentralized oracle ([Chainlink, Band, UMA, etc.](https://www.coingecko.com/en/categories/oracle)), Uniswap v3 TWAP or similar 37 | 38 | **Explanation** 39 | 40 | Oracle price manipulation changes the health of each borrowed position and can lead to bad debt, especially when combined with flashloans 41 | 42 | **Links** 43 | 44 | - [Compound DAI liquidation](https://www.comp.xyz/t/dai-liquidation-event/642) 45 | 46 | ## 3. What are the collateral factors and borrowing curves used for different tokens? 47 | 48 | **Incorrect** 49 | 50 | Much higher borrowing factor permitted compared to Compound (or Aave), much lower interest rate curve to Compound (or Aave) 51 | 52 | **Correct** 53 | 54 | Similar borrowing factor and interest rate curves to Compound (or Aave) 55 | 56 | **Explanation** 57 | 58 | The risk of bad debt is higher in adverse market conditions when there is a greater fraction of assets that is borrowed 59 | 60 | **Links** 61 | 62 | - [Compound's regular risk modelling with Gauntlet](https://risk.gauntlet.network/protocols/compound) 63 | 64 | ## 4. What mitigations exist to mitigate the risk of a toxic liquidation spiral? 65 | 66 | **Incorrect** 67 | 68 | None, the protocol did not consider this edge case in detail 69 | 70 | **Correct** 71 | 72 | Many options exist with varying degrees of impact: 73 | - Apply a dynamic incentive or closing factor during the liquidation process, which reduces the reward for liquidators as the loan nears the toxic liquidation threshold 74 | - Allow markets to be quickly (or automatically) frozen in certain market conditions, in line with [this research](https://arxiv.org/abs/2212.07306) 75 | - Choosing borrow caps and and collateral factors on assets strategically to minimize the risk of bad debt for each asset depending on current market liquidity and recent volatility 76 | 77 | **Explanation** 78 | 79 | Any DeFi protocol that allows borrowing must enforce liquidations to avoid the accumulation of bad debt. The most common incentive design is to give the liquidator a fraction of the liquidated amount as a reward. If there is a fast enough price movement, the reward amount given to the liquidator could create bad debt in the protocol, which can result in a liquidation spiral. This spiral is a result of one liquidation causing the borrower position to become less healthy (higher ratio of borrowed assets to collateral) after a liquidation happens, triggering more liquidations. 80 | 81 | **Links** 82 | 83 | - [CRV bad debt in Aave](https://governance.aave.com/t/arc-repay-excess-debt-in-crv-market-for-aave-v2-eth/10779) 84 | - [OpenZeppelin 2019 finding about "Counterproductive Incentives"](https://blog.openzeppelin.com/compound-audit) 85 | - [Toxic liquidations whitepaper](https://arxiv.org/abs/2212.07306) 86 | - [OVIX hack](https://0vixprotocol.medium.com/0vix-exploit-post-mortem-15c882dcf479) 87 | -------------------------------------------------------------------------------- /docs/cryptography.md: -------------------------------------------------------------------------------- 1 | # Cryptography 2 | 3 | Many cryptographic primitives are used by protocols. These can often have implementation mistakes when a common library is not used or when key values are improperly set. 4 | 5 | Other resources: 6 | 7 | - None currently 8 | 9 | ## 1. Is the Merkle proof validation done properly? 10 | 11 | **Incorrect** 12 | 13 | No 14 | 15 | **Correct** 16 | 17 | Yes 18 | 19 | **Explanation** 20 | 21 | TODO and improve the focus of the question 22 | 23 | **Links** 24 | 25 | - [OpenSea Merkle Audit Finding](https://github.com/code-423n4/2022-05-opensea-seaport-findings/issues/168) 26 | - [Binance bridge vulnerability](https://medium.com/immunefi/hack-analysis-binance-bridge-october-2022-2876d39247c1) 27 | - [OpenZeppelin merkle multiproof vulnerability in OZ >=4.7.0 <4.9.2](https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-wprv-93r4-jj2p) 28 | 29 | ## 2. Is the Merkle root set to a non-zero value? 30 | 31 | **Incorrect** 32 | 33 | No 34 | 35 | **Correct** 36 | 37 | Yes 38 | 39 | **Explanation** 40 | 41 | The default value of an integer in solidity is zero. So if valid proofs are stored in a mapping that maps the proof to the root, then invalid proofs map to a value of zero, which is the same as the valid root if the root is set to zero. This allows invalid proofs to be accepted because there is inadequate differentiation between valid and invalid proofs. 42 | 43 | **Links** 44 | 45 | - [Nomad bridge hack](https://medium.com/nomad-xyz-blog/nomad-bridge-hack-root-cause-analysis-875ad2e5aacd) 46 | 47 | ## 3. Is ECDSA `recover` malleable? 48 | 49 | **Incorrect** 50 | 51 | No 52 | 53 | **Correct** 54 | 55 | Yes 56 | 57 | **Explanation** 58 | 59 | TODO and improve the focus of the question 60 | 61 | **Links** 62 | 63 | - [Deeper dive into ECDSA signature malleability](https://0xsomeone.medium.com/b002-solidity-ec-signature-pitfalls-b24a0f91aef4) 64 | - [Polygon $2 million bug bounty](https://medium.com/immunefi/polygon-lack-of-balance-check-bugfix-postmortem-2-2m-bounty-64ec66c24c7d) 65 | - [OpenZeppelin ECDSA recover vulnerability in OZ >= 4.1.0 < 4.7.3](https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-4h98-2769-gh6h) 66 | - [Signature malleability PoC](https://github.com/pcaversaccio/malleable-signatures) 67 | 68 | ## 4. Is the result of solidity's `ecrecover` checked for a return value of 0? 69 | 70 | **Incorrect** 71 | 72 | No, the return value from `ecrecover` is not checked for a value of 0. 73 | 74 | **Correct** 75 | 76 | Yes, the code will revert if `ecrecover` returns a value of 0. 77 | 78 | **Explanation** 79 | 80 | [The solidity docs](https://docs.soliditylang.org/en/v0.8.20/units-and-global-variables.html#mathematical-and-cryptographic-functions) explain that `ecrecover` will return zero on error. If there is an error, the code should revert instead of continuing with the assumption that the recovered value is zero. 81 | 82 | **Links** 83 | 84 | - [Solidity docs describing ecrecover](https://docs.soliditylang.org/en/v0.8.20/units-and-global-variables.html#mathematical-and-cryptographic-functions) 85 | - OpenZeppelin's [ECDSA.sol `tryRecover()` avoids this issue as the comments explain](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/1a77a508f93e2df058cb082def4753a060aefa8f/contracts/utils/cryptography/ECDSA.sol#L147-L155) 86 | - Code4rena has many findings [related to a missing zero check for ecrecover](https://github.com/search?q=org%3Acode-423n4+ecrecover+check&type=issues), including [this one](https://github.com/code-423n4/2021-08-gravitybridge-findings/issues/61) and [this one](https://github.com/code-423n4/2022-07-golom-findings/issues/357). -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # About 2 | 3 | The open source knowledge repository for common smart contract bugs. 4 | 5 | The goal is to make a comprehensive checklist of common smart contract errors that can be used in many different contexts. This list intends to make it clearer what is an incorrect and correct pattern looks like to make it easier for anyone to better understand these common issues. 6 | 7 | Is something missing? Review the [contributing guidelines](../CONTRIBUTING.md) and open a PR! 8 | 9 | ## How to run locally 10 | 11 | This project is [built with MkDocs](https://squidfunk.github.io/mkdocs-material/). To run the docs locally, install the Python `mkdocs-material` package with `pip install mkdocs-material` or `pip3 install mkdocs-material`. After the package is installed, navigate to the top level directory of this project and run `mkdocs serve`. 12 | 13 | ## Seriously, why another security checklist?! 14 | 15 | This checklist of security issues in smart contracts aims to differentiate itself in a few ways: 16 | 17 | 1. Seek community contributions rather than attempting a solo effort 18 | 2. Give an explanation about what differentiates a correct implementation from an incorrect implementation, making it easier for anyone (security novices included) to avoid common errors 19 | 3. Link to additional information related to each vulnerability 20 | 4. Provide a nicer layout rendering than a markdown file -------------------------------------------------------------------------------- /docs/layer2.md: -------------------------------------------------------------------------------- 1 | # Deploying on other EVM-compatible (Arbitrum, Optimism, Gnosis, etc.) 2 | 3 | Protocols that will be deployed on multiple chains may require custom modifications for each individual chain because each chain is slightly different in key ways. One common multichain deployment option is to deploy on mainnet Ethereum and an L2 like Arbitrum or Optimism. 4 | 5 | Other resources: 6 | 7 | - [EVM Diff, differences between EVM compatible chains](https://www.evmdiff.com/) 8 | 9 | ## 1. If Chainlink is used, is there a check for sequencer uptime? 10 | 11 | **Incorrect** 12 | 13 | No 14 | 15 | **Correct** 16 | 17 | Sequencer uptime is verified 18 | 19 | **Explanation** 20 | 21 | [Old price data may be used](https://twitter.com/bytes032/status/1653943092427325448) if the protocol is not aware that the sequencer is down. 22 | 23 | **Links** 24 | 25 | - [Chainlink recommended sequencer check code](https://docs.chain.link/data-feeds/l2-sequencer-feeds#example-code) 26 | 27 | ## 2. Is block.number used anywhere? 28 | 29 | **Incorrect** 30 | 31 | Yes, block.number is used on Optimism, Arbitrum, or a similar L2 32 | 33 | **Correct** 34 | 35 | No, `block.timestamp` is used instead of `block.number` 36 | 37 | **Explanation** 38 | 39 | Block production is not constant on L2 chains, meaning `block.timestamp` is a better choice than `block.number` in most cases. 40 | 41 | **Links** 42 | 43 | - [block.timestamp recommended by Optimism docs](https://community.optimism.io/docs/developers/build/differences/#added-opcodes) 44 | - [block.timestamp recommended by Arbitrum docs](https://developer.arbitrum.io/time#block-numbers-arbitrum-vs-ethereum) 45 | 46 | ## 3. Is CREATE2 used in contracts deployed to zkEVMs (like zkSync Era)? 47 | 48 | **Incorrect** 49 | 50 | Yes 51 | 52 | **Correct** 53 | 54 | No 55 | 56 | **Explanation** 57 | 58 | zkEVMs can compute CREATE2 addresses differently than on ETH mainnet. Code copied from ETH mainnet to calculate the address of the contract deployed with CREATE2 may not work as expected. 59 | 60 | **Links** 61 | 62 | - [Tweet from pcaversaccio describing the difference](https://twitter.com/pcaversaccio/status/1701938364696363103) 63 | 64 | ## 4. If deployed on Gnosis chain (xDAI), are reentrant tokens considered? 65 | 66 | **Incorrect** 67 | 68 | No 69 | 70 | **Correct** 71 | 72 | Yes 73 | 74 | **Explanation** 75 | 76 | Gnosis Chain cross-chain tokens have a `onTokenTransfer()` hook that enabled reentrancy. The Gnosis bridge creates a ERC677 tokens on Gnosis Chain for these tokens, which means protocols like Compound Finance cannot be used on xDAI safely unless modified to protect against reentrancy. 77 | 78 | **Links** 79 | 80 | - [Gnosis bridge details](https://docs.gnosischain.com/bridges/tutorials/using-omnibridge/) 81 | - [Hundred Finance and Agave Finance hacks](https://medium.com/immunefi/a-poc-of-the-hundred-finance-heist-4121f23a098) 82 | 83 | ## 5. Do any token addresses consider if a token is bridged or native? 84 | 85 | **Incorrect** 86 | 87 | A difference between bridged or native tokens was not considered. 88 | 89 | **Correct** 90 | 91 | Yes, the different types of tokens were considered and the correct choice is made. 92 | 93 | **Explanation** 94 | 95 | Some tokens, like USDC, have a bridged and native form. For example, USDC.e on Arbitrum, Avalanche, and Optimism is the bridged form of USDC. Circle launched a native USDC on these chains after the bridged tokens already existed. If the protocol involves any tokens that may be bridged, it is important to consider which token address to use. 96 | 97 | **Links** 98 | 99 | - [Circle announcement of Optimism native USDC](https://www.circle.com/blog/now-available-usdc-on-op-mainnet) 100 | - [Circle announcement of Arbitrum native USDC](https://www.circle.com/blog/arbitrum-usdc-now-available) 101 | 102 | ## 6. If deployed on Blast chain, is it claiming fees? 103 | 104 | **Incorrect** 105 | 106 | No. 107 | 108 | **Correct** 109 | 110 | Yes, deployed contracts are configured to receive and claim gas from Blast. 111 | 112 | **Explanation** 113 | 114 | Blast redirects sequencer fees to the DApps that induced them, allowing smart contract developers to have an additional source of revenue. The contracts have to be configured to receive and claim gas fees. 115 | 116 | **Links** 117 | 118 | - [Blast docs for receiving and claiming fees](https://docs.blast.io/building/guides/gas-fees#overview) 119 | -------------------------------------------------------------------------------- /docs/oracle.md: -------------------------------------------------------------------------------- 1 | # Oracle price data 2 | 3 | Oracles are a common choice to receive price data for assets. The price data from oracles can be harder to manipulate than price data from a DeFi protocol's swap pool, but there are common oracle integration issues that should be kept in mind. 4 | 5 | Other resources: 6 | 7 | - [Market Manipulation vs. Oracle Exploits](https://chain.link/education-hub/market-manipulation-vs-oracle-exploits) 8 | 9 | ## 1. Is the spot price of a pool used? 10 | 11 | **Incorrect** 12 | 13 | Yes, spot price is used and it can be manipulated by flashloans 14 | 15 | **Correct** 16 | 17 | A decentralized oracle ([Chainlink, Band, UMA, etc.](https://www.coingecko.com/en/categories/oracle)), Uniswap v3 TWAP or similar 18 | 19 | **Explanation** 20 | 21 | Flashloan price manipulation has caused many protocol hacks, making price manipulation hacks one of the most common attack vectors 22 | 23 | **Links** 24 | 25 | - [samczsun's oracle price guide](https://shouldiusespotpriceasmyoracle.com/) 26 | 27 | ## 2. Are variable decimals for different token pair price feeds accounted for? 28 | 29 | **Incorrect** 30 | 31 | No, a constant decimals value is hardcoded 32 | 33 | **Correct** 34 | 35 | Yes 36 | 37 | **Explanation** 38 | 39 | Incorrect decimals can lead to accounting errors 40 | 41 | **Links** 42 | 43 | - [USD/AMPL Chainlink price feed has 18 decimals, not 8 decimals](https://etherscan.io/address/0xe20ca8d7546932360e37e9d72c1a47334af57706#readContract#F3) 44 | 45 | ## 3. If Uniswap v3 TWAP is used for price data, is post-merge PoS manipulation accounted for? 46 | 47 | **Incorrect** 48 | 49 | No, TWAP is fully trusted 50 | 51 | **Correct** 52 | 53 | Yes 54 | 55 | **Explanation** 56 | 57 | Incorrect decimals can lead to accounting errors 58 | 59 | **Links** 60 | 61 | - [Euler oracle manipulation tool](https://oracle.euler.finance/) and [usage instructions](https://medium.com/eulerfinance/uniswap-oracle-attack-simulator-42d18adf65af) 62 | - [Uniswap analysis of TWAP manipulation in PoS](https://blog.uniswap.org/uniswap-v3-oracles) 63 | 64 | # Chainlink Oracle 65 | 66 | ## 1. Is a deprecated Chainlink function used, such as `latestAnswer()`, `latestRound()`, or `getTimestamp()`? 67 | 68 | **Incorrect** 69 | 70 | Yes 71 | 72 | **Correct** 73 | 74 | No 75 | 76 | **Explanation** 77 | 78 | Deprecated functions may not be supported in the future, which could cause a denial of service 79 | 80 | **Links** 81 | 82 | - [Chainlink deprecated functions](https://docs.chain.link/data-feeds/api-reference) 83 | 84 | ## 2. Is there proper validation of `latestRoundData()`? 85 | 86 | **Incorrect** 87 | 88 | No 89 | 90 | **Correct** 91 | 92 | Yes, price is confirmed to be [in the range of minAnswer and maxAnswer limits](https://docs.chain.link/data-feeds#check-the-latest-answer-against-reasonable-limits), the [timestamp of the latest answer is checked](https://docs.chain.link/data-feeds#check-the-timestamp-of-the-latest-answer) against zero and a stale feed threshold that depends on the update frequency of the oracle for each specific token 93 | 94 | **Explanation** 95 | 96 | Insufficient validation of oracle can lead to the acceptance of bad data 97 | 98 | **Links** 99 | 100 | - [Compound fork bad debt accumulation during Luna crash](https://rekt.news/venus-blizz-rekt/) 101 | 102 | ## 3. Is the price query in a try/catch? 103 | 104 | **Incorrect** 105 | 106 | No 107 | 108 | **Correct** 109 | 110 | Yes, `latestRoundData` call is in a try/catch block 111 | 112 | **Explanation** 113 | 114 | Access to price feed data may be removed due to the multisig ownership of Chainlink's EACAggregatorProxy contract which is queried for price data. If uptime is a key part of a protocol's design and the Chainlink multisig is not considered a trusted entity, a backup mode of operation should exist in the `catch` block of the try/catch price query to handle the edge case where the primary Chainlink price feed is not available. 115 | 116 | **Links** 117 | 118 | - ["ChainLink Price Feeds" section of OpenZeppelin post](https://blog.openzeppelin.com/secure-smart-contract-guidelines-the-dangers-of-price-oracles) -------------------------------------------------------------------------------- /docs/proxies.md: -------------------------------------------------------------------------------- 1 | # Proxies and Upgradeable Code 2 | 3 | Proxies are a common tool to allow for smart contract code to receive upgrades. A proxy contract acts as a pointer to a logic contract using delegatecall, and the logic contract contains the implementation logic. If the proxy contract is modified to point to a different logic contract address, the implementation logic is changed. 4 | 5 | Other resources: 6 | 7 | - [OpenZeppelin Proxy Pattern](https://docs.openzeppelin.com/upgrades-plugins/1.x/proxies) 8 | - [yAcademy Proxies Research](https://proxies.yacademy.dev/) 9 | 10 | ## 1. Is the UUPS proxy initialized? 11 | 12 | **Incorrect** 13 | 14 | No 15 | 16 | **Correct** 17 | 18 | Yes 19 | 20 | **Explanation** 21 | 22 | An uninitialized proxy can be initialized by anyone. The user that calls the initialize function is granted special privileges for the proxy contract. 23 | 24 | **Links** 25 | 26 | - [Wormhole, largest bug bounty](https://medium.com/immunefi/wormhole-uninitialized-proxy-bugfix-review-90250c41a43a) 27 | - [Aave v2](https://medium.com/aave/aave-security-newsletter-546bf964689d) 28 | - [Agave v2 (Aave fork)](https://medium.com/@hacxyk/forked-protocols-are-not-battle-tested-agave-uninitialized-proxy-vulnerability-6b5d587b3a07) 29 | - [Teller](https://medium.com/immunefi/teller-bug-fix-postmorten-and-bug-bounty-launch-b3f67a65c5ac) 30 | - [Harvest Finance](https://medium.com/immunefi/harvest-finance-uninitialized-proxies-bug-fix-postmortem-ea5c0f7af96b) 31 | 32 | ## 2. Does the logic contract behind the proxy contain selfdestruct? 33 | 34 | **Incorrect** 35 | 36 | Yes 37 | 38 | **Correct** 39 | 40 | No, `selfdestruct` is not found in the contracts or the contract is not a logic contract behind a proxy contract 41 | 42 | **Explanation** 43 | 44 | If the logic contract behind a proxy contains `selfdestruct`, the proxy can be deleted, which can cause a denial of service. If a metamorphic contract created with CREATE2 contains `selfdestruct`, then the contract code can be replaced in a similar way to upgrading code behind a proxy. 45 | 46 | **Links** 47 | 48 | - [Parity Wallet hack](https://www.parity.io/blog/a-postmortem-on-the-parity-multi-sig-library-self-destruct/) and [OpenZeppelin writeup](https://blog.openzeppelin.com/on-the-parity-wallet-multisig-hack-405a8c12e8f7/) (note: the contract was initialized but had no protection against a second call to `initialize()`) 49 | - [Paradigm CTF 2021 "Vault"](https://github.com/paradigmxyz/paradigm-ctf-2021/tree/master/vault) 50 | - [Ethernaut Level 25 "Motorbike"](https://github.com/OpenZeppelin/ethernaut/blob/master/contracts/contracts/levels/Motorbike.sol) 51 | - [OpenZeppelin proxy vulnerability](https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-5vp3-v4hc-gx76) 52 | - [iosiro blog post about OpenZeppelin vulnerability](https://www.iosiro.com/blog/openzeppelin-uups-proxy-vulnerability-disclosure) 53 | 54 | ## 3. Is the contract (not necessarily a proxy contract) created with CREATE2 or CREATE3 and the contract contains selfdestruct? 55 | 56 | **Incorrect** 57 | 58 | Yes 59 | 60 | **Correct** 61 | 62 | No, `selfdestruct` is not found in the contracts or the contract was not created with CREATE2 or CREATE3 63 | 64 | **Explanation** 65 | 66 | A CREATE2 or CREATE3 contract that contains selfdestruct can be destroyed and replaced with a new contract at the same address. If a metamorphic contract created with CREATE2 contains `selfdestruct`, then the contract code can be replaced in a similar way to upgrading code behind a proxy. 67 | 68 | **Links** 69 | 70 | - [Rajeev forum post about CREATE2 security implications](https://ethereum-magicians.org/t/potential-security-implications-of-create2-eip-1014/2614) 71 | - [CertiK metamorphic contract detector tool](https://medium.com/certik/introducing-certiks-create2-audit-tool-2c75f0b53f54) 72 | - [a16z metamorphic contract detector tool](https://a16zcrypto.com/metamorphic-smart-contract-detector-tool/) 73 | - [PoC metamorphic contract detector tool](https://gist.github.com/engn33r/ec2d8f176bff962064afdadedb2d6faf) 74 | 75 | ## 4. Does the upgraded logic contract have the same state variable layout as the contract it replaces? 76 | 77 | **Incorrect** 78 | 79 | No 80 | 81 | **Correct** 82 | 83 | Yes, new state variables are only appended to the list of existing state variables. Even better, the new state variables are filling slots that were already reserved using a pattern like [OpenZeppelin contact's storage gap](https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps). 84 | 85 | **Explanation** 86 | 87 | If the storage variable layout is changed, a storage collision can happen where the variable names in the upgraded contract to not match the variables that are stored in the corresponding storage slots. The storage layout should always consider inheritance, so flattening the contracts to more easily view the storage variables can sometimes be a useful manual approach. Automated tools can also reveal the storage layout of a contract and help verify that no storage collision happens as a result of a contract upgrade. 88 | 89 | **Links** 90 | 91 | - [Furucombo](https://medium.com/furucombo/furucombo-post-mortem-march-2021-ad19afd415e) (Related writeups [here](https://rekt.news/furucombo-rekt/) and [here](https://github.com/OriginProtocol/security/blob/master/incidents/2021-02-27-Furucombo.md)) 92 | - [Audius](https://blog.audius.co/article/audius-governance-takeover-post-mortem-7-23-22) (Related writeup [here](https://rekt.news/audius-rekt/)) 93 | - [Solidity by Example](https://solidity-by-example.org/hacks/delegatecall/) 94 | - [Ethernaut Level 6 "Delegation"](https://github.com/OpenZeppelin/ethernaut/blob/master/contracts/contracts/levels/Delegation.sol) 95 | - [Ethernaut Level 16 "Preservation"](https://github.com/OpenZeppelin/ethernaut/blob/master/contracts/contracts/levels/Preservation.sol) 96 | - [Ethernaut Level 24 "Puzzle Wallet"](https://github.com/OpenZeppelin/ethernaut/blob/master/contracts/contracts/levels/PuzzleWallet.sol) 97 | - [Underhanded Solidity 2020 entry 4](https://github.com/ethereum/solidity-underhanded-contest/tree/master/2020/submissions_2020/submission4_JaimeIglesias) from Jaime Iglesias 98 | - [OpenZeppelin explanation](https://docs.openzeppelin.com/upgrades-plugins/1.x/proxies#storage-collisions-between-implementation-versions) -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: Smart Contract Security Checklist 2 | theme: 3 | name: material 4 | features: 5 | - header.autohide 6 | palette: 7 | 8 | # Palette toggle for light mode 9 | - scheme: default 10 | primary: blue 11 | toggle: 12 | icon: material/brightness-7 13 | name: Switch to dark mode 14 | 15 | # Palette toggle for dark mode 16 | - scheme: slate 17 | primary: blue 18 | toggle: 19 | icon: material/brightness-4 20 | name: Switch to light mode 21 | -------------------------------------------------------------------------------- /other-checklists.md: -------------------------------------------------------------------------------- 1 | # Other checklists 2 | 3 | A list of other checklists which should be included into this all-inclusive checklist 4 | 5 | - https://github.com/YAcademy-Residents/CommonWeb3SecurityIssues 6 | - https://github.com/harendra-shakya/smart-contract-attack-vectors 7 | - https://github.com/Decurity/audit-checklists/blob/master/cdp.md 8 | - https://github.com/Decurity/audit-checklists/blob/master/lsd.md 9 | - https://github.com/securing/SCSVS 10 | - https://github.com/tonisives/smart-contract-attack-vectors 11 | - https://github.com/0xprinc/checks-while-hacks 12 | - https://github.com/Quillhash/Solidity-Attack-Vectors 13 | - https://github.com/manifoldfinance/defi-threat --------------------------------------------------------------------------------