Secureum Book
  • 🛡️Secureum Bootcamp
    • 🛡️Secureum Bootcamp
    • 🙌Participate
    • 📜History
  • 📚LEARN
    • Introduction
      • 🔷1. Ethereum Basics
        • 1.1 Ethereum: Concept, Infrastructure & Purpose
        • 1.2 Properties of the Ethereum Infrastructure
        • 1.3 Ethereum vs. Bitcoin
        • 1.4 Ethereum Core Components
        • 1.5 Gas Metering: Solving the Halting Problem
        • 1.6 web2 vs. web3: The Paradigm Shift
        • 1.7 Decentralization
        • 1.8 Cryptography, Digital Signature & Keys
        • 1.9 Ethereum State & Account Types
        • 1.10 Transactions: Properties & Components
        • 1.11 Contract Creation
        • 1.12 Transactions, Messages & Blockchain
        • 1.13 EVM (Ethereum Virtual Machine) in Depth
        • 1.14 Transaction Reverts & Data
        • 1.15 Block Explorer
        • 1.16 Mainnet & Testnets
        • 1.17 ERCs & EIPs
        • 1.18 Legal Aspects in web3: Pseudonymity & DAOs
        • 1.19 Security in web3
        • 1.20 web2 Timescales vs. web3 Timescales
        • 1.21 Test-in-Prod. SSLDC vs. Audits
        • Summary: 101 Keypoints
      • 🌀2. Solidity
        • 2.1 Solidity: Influence, Features & Layout
        • 2.2 SPDX & Pragmas
        • 2.3 Imports
        • 2.4 Comments & NatSpec
        • 2.5 Smart Contracts
        • 2.6 State Variables: Definition, Visibility & Mutability
        • 2.7 Data Location
        • 2.8 Functions
        • 2.9 Events
        • 2.10 Solidity Typing
        • 2.11 Solidity Variables
        • 2.12 Address Type
        • 2.13 Conversions
        • 2.14 Keywords & Shorthand Operators
        • 2.15 Solidity Units
        • 2.16 Block & Transaction Properties
        • 2.17 ABI Encoding & Decoding
        • 2.18 Error Handling
        • 2.19 Mathematical & Cryptographic Functions
        • 2.20 Control Structures
        • 2.21 Style & Conventions
        • 2.22 Inheritance
        • 2.23 EVM Storage
        • 2.24 EVM Memory
        • 2.25 Inline Assembly
        • 2.26 Solidity Version Changes
        • 2.27 Security Checks
        • 2.28 OpenZeppelin Libraries
        • 2.29 DAppSys Libraries
        • 2.30 Important Protocols
        • Summary: 201 Keypoints
      • 🔏3. Security Pitfalls & Best Practices
        • 3.1 Solidity Versions
        • 3.2 Access Control
        • 3.3 Modifiers
        • 3.4 Constructor
        • 3.5 Delegatecall
        • 3.6 Reentrancy
        • 3.7 Private Data
        • 3.8 PRNG & Time
        • 3.9 Math & Logic
        • 3.10 Transaction Order Dependence
        • 3.11 ecrecover
        • 3.12 Unexpected Returns
        • 3.13 Ether Accounting
        • 3.14 Transaction Checks
        • 3.15 Delete Mappings
        • 3.16 State Modification
        • 3.17 Shadowing & Pre-declaration
        • 3.18 Gas & Costs
        • 3.19 Events
        • 3.20 Unary Expressions
        • 3.21 Addresses
        • 3.22 Assertions
        • 3.23 Keywords
        • 3.24 Visibility
        • 3.25 Inheritance
        • 3.26 Reference Parameters
        • 3.27 Arbitrary Jumps
        • 3.28 Hash Collisions & Byte Level Issues
        • 3.29 Unicode RTLO
        • 3.30 Variables
        • 3.31 Pointers
        • 3.32 Out-of-range Enum
        • 3.33 Dead Code & Redundant Statements
        • 3.34 Compiler Bugs
        • 3.35 Proxy Pitfalls
        • 3.36 Token Pitfalls
        • 3.37 Special Token Pitfalls
        • 3.38 Guarded Launch Pitfalls
        • 3.39 System Pitfalls
        • 3.40 Access Control Pitfalls
        • 3.41 Testing, Unused & Redundand Code
        • 3.42 Handling Ether
        • 3.43 Application Logic Pitfalls
        • 3.44 Saltzer & Schroeder's Design Principles
        • Summary: 201 Keypoints
      • 🗜️4. Audit Techniques & Tools
        • 4.1 Audit
        • 4.2 Analysis Techniques
        • 4.3 Specification, Documentation & Testing
        • 4.4 False Positives & Negatives
        • 4.5 Security Tools
        • 4.6 Audit Process
        • Summary: 101 Keypoints
      • ☝️5. Audit Findings
        • 5.1 Criticals
        • 5.2 Highs
        • 5.3 Mediums
        • 5.4 Lows
        • 5.5 Informationals
        • Summary: 201 Keypoints
  • 🌱CARE
    • CARE
      • CARE Reports
  • 🚩CTFs
    • A-MAZE-X CTFs
      • Secureum A-MAZE-X
      • Secureum A-MAZE-X Stanford
      • Secureum A-MAZE-X Maison de la Chimie Paris
Powered by GitBook
On this page
  • Reentrancy via ERC777
  • OOG in transfer() & send()
  1. LEARN
  2. Introduction
  3. 3. Security Pitfalls & Best Practices

3.6 Reentrancy

The reentrancy security pitfall is perhaps unique to smart contracts where external calls made to contracts can result in what can be thought of as callbacks to the called contract itself.

So for example, if there is a contract C1, that makes a call to an external contract C2, where C2 could potentially be untrusted could be malicious because it is not developed by the same team or within the same project as C1, then that external contract C2 could call back into C1 to the same function that called it or to any other function of C1 that allows such a call.

This could be exploited to do malicious things, such as multiple withdrawals or something less harmful, such as out of order emission of events. There have been multiple exploits that have taken advantage of this class of reentrancy attacks, some of them are historical in nature such as the DAO hack on Ethereum.

So this class of security vulnerabilities, that is specific to smart contracts needs to be paid attention to, the best practice to prevent such reentrancy vulnerabilities from being exploited is to follow what is known as the Checks-Effects-Interactions pattern (the CEI pattern for short), where the interactions with external potentially untrusted contracts is only made after performing all the checks and all the effects where effects are nothing, but changes to the state of the calling contract, so that any anticipated side-effects of interactions with the external contracts are already reflected in the state of the calling contract.

So this CEI pattern is recommended as a best practice to be followed in all functions that are making external contract calls specifically to contact calls that could be malicious because they're untrusted. The other best practice is to use what are known as reentrancy guards, we talked about this in the context of the reentrancy guard library from OpenZeppelin where a a nonReentrant modifier is provided. This modifier when applied to specific functions prevents them from being called within a callback, so it avoids any reentrances to that function itself.

Reentrancy via ERC777

This security pitfall is related to the use of ERC777 standard, the potential for re-entrancy vulnerabilities due to the callbacks it supports.

Remember that ERC777 standard is considered as an extension to the ERC20 standard it's considered as making improvements to it. One improvement is the notion of hooks that it supports during token transfers, if such an ERC777 token contract is potentially malicious, then it could use these hooks to cause reentrancy into the calling contract.

So for example, if there's a contract C1 that calls an ERC777 token contract that is malicious, then that contract could use the hook functionality to cause a reentrancy into the calling contract C1 and take advantage of it as we just mentioned.

The best practice again is to follow the Checks Effects Interaction (CEI) pattern in the calling contract and also to consider the use of reentrancy guards.

OOG in transfer() & send()

This security pitfall is related to the use of the transfer and send primitives in Solidity.

These primitives were introduced as reentrancy mitigations, because they only forward 2300 Gas to the called contract, which is typically sufficient only for basic processing such as emitting a few logs or something even simpler, this Gas is not enough to make a real currency call back to the calling contract which requires more than 2300 gas.

So this has been recommended for a long time as a security best practice for preventing reentrancy attacks however over time some of the opcodes have been reprised when it comes to their Gas usage, so their Gas Cost has increased in some of the recent hard forks on Ethereum and because of that the use of these primitives that enforce the Gas subsidiary 2300 Gas could break the contract because it might not allow the called contract to even do the basic processing that we just talked about.

So the latest security best practice recommendation is to not rely on transfer() and send() as reentrancy mitigations, but instead to use the low-level call() directly that does not have those hard-coded Gas Limits and couple that with a CEI pattern or reentrancy guard or both for re-entrance mitigation.

Previous3.5 DelegatecallNext3.7 Private Data

Last updated 1 year ago

📚
🔏