Free 30-min Web3 Consultation
Book Now
Smart Contract Security Audits
Learn More
Custom DeFi Protocol Development
Explore
Full-Stack Web3 dApp Development
View Services
Free 30-min Web3 Consultation
Book Now
Smart Contract Security Audits
Learn More
Custom DeFi Protocol Development
Explore
Full-Stack Web3 dApp Development
View Services
Free 30-min Web3 Consultation
Book Now
Smart Contract Security Audits
Learn More
Custom DeFi Protocol Development
Explore
Full-Stack Web3 dApp Development
View Services
Free 30-min Web3 Consultation
Book Now
Smart Contract Security Audits
Learn More
Custom DeFi Protocol Development
Explore
Full-Stack Web3 dApp Development
View Services
LABS
Glossary

Reentrancy Lock

A reentrancy lock is a smart contract security pattern that prevents reentrancy attacks by blocking recursive calls during a function's execution.
Chainscore © 2026
definition
SECURITY PATTERN

What is a Reentrancy Lock?

A reentrancy lock is a smart contract security mechanism that prevents a function from being called again before its initial execution has completed, thereby blocking reentrancy attacks.

A reentrancy lock is a defensive programming pattern, also known as a mutex (mutual exclusion) or non-reentrant guard, implemented in a smart contract to prevent a critical vulnerability. It works by setting a boolean state variable—often named locked, _notEntered, or _status—to true at the start of a function's execution and resetting it to false only after all logic and state changes are finalized. This creates a simple check-and-set barrier: if the lock is already engaged when the function is called, the transaction reverts, blocking recursive entry.

This mechanism directly counters the classic reentrancy attack, where a malicious contract exploits the checks-effects-interactions pattern violation. In such an attack, an external call (the interaction) to an untrusted contract is made before the calling contract's state is updated (the effects). The called contract can then recursively call back into the original function, which, seeing its state unchanged, may allow funds to be drained multiple times. The reentrancy lock acts as a circuit breaker, making the function atomic from the perspective of external callers.

The most common and secure implementation is the ReentrancyGuard provided by libraries like OpenZeppelin Contracts. Developers apply it using a modifier, such as nonReentrant, on vulnerable functions. It is considered a best practice for any function that performs external calls or transfers value (e.g., call, transfer, send). While effective, it is one layer of defense and should be combined with other secure patterns like pulling payments and rigorous adherence to the checks-effects-interactions order.

how-it-works
MECHANISM

How a Reentrancy Lock Works

A reentrancy lock is a fundamental security pattern in smart contract development that prevents a specific class of vulnerability by blocking recursive callback attacks during a function's execution.

A reentrancy lock, often implemented as a mutex (mutual exclusion) flag, is a state variable that acts as a guard. Before executing sensitive logic—such as transferring funds or updating balances—a function checks if the lock is false (unlocked). It immediately sets it to true (locked), executes the critical operations, and then resets the lock to false upon completion. This simple checks-effects-interactions pattern ensures the contract's state is fully resolved before any external calls are allowed to re-enter. The most common implementation is the nonReentrant modifier from libraries like OpenZeppelin's ReentrancyGuard.

The necessity for this lock stems from the reentrancy attack vector. In Ethereum and similar blockchains, when a contract makes an external call to another contract (e.g., sending Ether via .call.value()), it can cede control flow. A malicious contract receiving the funds can have a fallback or receive function that calls back into the original function. Without a lock, this recursive call can re-enter before the original function's state updates (like deducting a balance) are finalized, allowing the attacker to drain funds in a loop. The infamous 2016 DAO hack exploited this exact vulnerability.

Implementing a reentrancy lock correctly requires careful consideration of function scope. The lock is typically applied at the function level, meaning reentrancy into the same function is prevented. However, developers must also be wary of cross-function reentrancy, where an attacker re-enters a different, state-sharing function. For maximum security, some designs use a single lock for an entire contract or employ more sophisticated patterns like reentrancy guards with counters to allow certain privileged, internal functions to be called while the lock is active, without exposing a vulnerability.

key-features
MECHANISM

Key Features of a Reentrancy Lock

A reentrancy lock is a state variable that prevents a function from being called recursively before its initial execution completes, a critical defense against reentrancy attacks.

01

Boolean State Variable

The core of a reentrancy lock is a boolean state variable (e.g., bool private locked;). This flag is set to true at the start of a vulnerable function and reset to false at the end, creating a mutual exclusion barrier. If a malicious callback attempts to re-enter the function, the initial require(!locked, "Reentrant call"); check will revert the transaction.

02

Checks-Effects-Interactions Pattern

A reentrancy lock enforces the Checks-Effects-Interactions pattern by design. The lock is a guard that ensures:

  • Checks: All pre-conditions (e.g., balances) are validated.
  • Effects: All state changes (e.g., updating balances) are committed.
  • Interactions: External calls (e.g., transfer) are made only after internal state is finalized and the lock is still active, preventing state corruption.
03

Modifier Implementation

The lock logic is typically encapsulated in a function modifier. This promotes code reuse and reduces errors. Example:

solidity
modifier nonReentrant() {
    require(!locked, "ReentrancyGuard: reentrant call");
    locked = true;
    _;
    locked = false;
}

Applying nonReentrant to a function automatically wraps it with the lock, simplifying contract security.

04

Prevents Cross-Function Reentrancy

A single, contract-wide reentrancy lock can also prevent cross-function reentrancy. This occurs when an attacker re-enters a different function that shares state with the vulnerable one. Because the locked flag is global, any function protected by the same modifier will be guarded against re-entry from any other protected function, closing a common attack vector.

05

Gas Overhead & Limitations

Using a reentrancy lock introduces minimal gas overhead (typically ~5k gas for SSTORE operations) but is crucial for security. Its key limitation is that it only protects functions using the specific modifier. It does not prevent:

  • Read-only reentrancy: Attacks that exploit price oracle updates or view functions.
  • Attacks on functions without the modifier.
  • Reentrancy between different contracts in a system.
security-considerations
REENTRANCY LOCK

Security Considerations & Best Practices

A reentrancy lock is a fundamental security pattern used to prevent reentrancy attacks, where a malicious contract can recursively call back into a vulnerable function before its state is finalized.

01

The Core Mechanism

A reentrancy lock (or mutex) is a boolean state variable that acts as a flag. When a function is entered, it checks if the lock is false (unlocked), sets it to true (locked), executes the critical logic, and then sets it back to false. This prevents any nested call from re-entering the same function path.

  • Key Variable: Typically a bool private locked = false;
  • Check-Effects-Interaction: The lock enforces this pattern by ensuring state changes happen before any external calls that could trigger reentrancy.
02

Implementation with `nonReentrant`

The most common implementation is a modifier, popularized by OpenZeppelin's ReentrancyGuard contract. This modifier wraps the function logic, providing a reusable and audited lock.

solidity
modifier nonReentrant() {
    require(!locked, "Reentrant call");
    locked = true;
    _;
    locked = false;
}

Using nonReentrant on functions that perform external calls (e.g., transfer, call) is a critical best practice.

03

Limitations & Subtle Attacks

While a basic lock prevents single-function reentrancy, developers must be aware of its scope:

  • Cross-Function Reentrancy: A lock on withdraw() doesn't protect transfer() if they share state. Use a single lock for all functions sharing critical state.
  • Cross-Contract Reentrancy: A lock in Contract A doesn't protect a state read from Contract B that A interacts with.
  • nonReentrant Ordering: The modifier must be placed first in the modifier list to lock before any other conditional checks.
04

Best Practice: Lock-Effects-Interaction

The definitive pattern for secure function design:

  1. Lock: Apply the reentrancy guard (e.g., nonReentrant modifier).
  2. Effects: Perform all internal state updates (e.g., reducing a user's balance).
  3. Interaction: Make the external call (e.g., sending ETH).

This ensures the contract's state is finalized and consistent before relinquishing control via an external call, which is the potential point of re-entry. This pattern is more robust than the older Checks-Effects-Interactions as it explicitly starts with the lock.

05

Historical Context: The DAO Hack

The 2016 attack on The DAO was the seminal reentrancy attack that resulted in the loss of 3.6 million ETH and led to the Ethereum hard fork. The vulnerable splitDAO function:

  • Sent ETH to the attacker before updating the attacker's internal token balance.
  • The attacker's fallback function recursively called back into splitDAO, draining funds in a loop.

This event cemented reentrancy locks and the Checks-Effects-Interactions pattern as mandatory security knowledge.

06

Related Security Primitives

Reentrancy locks work alongside other critical patterns:

  • Pull-over-Push Payments: Instead of pushing funds (which can be re-entered), let users withdraw them (pull), removing reentrancy risk from the core logic.
  • State Machine Patterns: Using explicit states (e.g., Locked, Unlocked) can provide more granular control for complex workflows.
  • Gas Limits: While not a defense, being aware that reentrancy attacks consume gas can inform risk assessment for functions with strict gas stipends.
PATTERN COMPARISON

Reentrancy Lock vs. Checks-Effects-Interactions

A comparison of two primary smart contract security patterns for preventing reentrancy attacks.

FeatureReentrancy Lock (Mutex)Checks-Effects-Interactions (CEI)

Core Mechanism

State variable flag preventing nested calls

Strict ordering of operations within a function

Implementation Complexity

Low

Medium

Gas Overhead

~5k gas per function (SLOAD/SSTORE)

< 1k gas (ordering only)

Protection Scope

Entire function

Specific state transitions within function

Common Standard

OpenZeppelin ReentrancyGuard

Solidity documentation best practice

State Update Timing

State updates can occur after external calls

State updates must occur before external calls

Risk if Misapplied

Reentrancy on other functions

Incorrect order reintroduces vulnerability

ecosystem-usage
SECURITY PATTERN

Ecosystem Usage & Standards

A reentrancy lock is a critical security pattern used to prevent reentrancy attacks in smart contracts by blocking recursive calls during the execution of a function.

01

The Core Mechanism

A reentrancy lock (or mutex) is a boolean state variable that acts as a flag. When a function is entered, it checks if the lock is false (unlocked), sets it to true (locked), executes the critical logic, and then resets it to false. This prevents any external contract from re-entering the function while the initial call is still in progress, blocking the classic reentrancy attack vector.

  • Key Variable: Often named locked, _notEntered, or _status.
  • Check-Effects-Interactions: The lock enforces this pattern by ensuring state changes happen before any external calls.
03

Cross-Function Reentrancy

A simple lock on a single function may not protect against cross-function reentrancy, where an attacker re-enters a different function that shares state with the vulnerable one. Mitigations include:

  • Single Lock for Entire Contract: Using one global lock for all sensitive functions (though this reduces composability).
  • Granular Locks: Implementing separate locks for different state variables or user balances.
  • Careful State Isolation: Ensuring functions do not share intermediate state vulnerable to interference.
04

Limitations & Trade-offs

While essential, reentrancy locks introduce specific trade-offs:

  • Gas Overhead: Adds a small gas cost for the state variable check and write.
  • Composability Reduction: A global lock can block legitimate, nested calls from other contracts, breaking certain DeFi composability patterns.
  • Not a Silver Bullet: Does not protect against other vulnerabilities like flash loan price manipulation or logic errors. It must be part of a broader security strategy including the checks-effects-interactions pattern.
05

Historical Context: The DAO Hack

The critical importance of reentrancy locks was demonstrated by The DAO hack in 2016, which led to the loss of 3.6 million ETH. The vulnerable contract's splitDAO function sent ETH before updating the user's internal token balance. An attacker's fallback function repeatedly re-entered splitDAO, draining funds. This event was the direct catalyst for the Ethereum network hard fork (creating Ethereum Classic) and established reentrancy protection as the foremost smart contract security lesson.

06

Related Security Primitives

Reentrancy locks work alongside other critical security patterns and standards:

  • Checks-Effects-Interactions: The foundational code ordering pattern the lock enforces.
  • Pull-over-Push Payments: Mitigates reentrancy by having users withdraw funds themselves.
  • ERC-20 / ERC-721: Token standards with their own transfer hooks that require careful integration with locks.
  • Static Analysis Tools: Tools like Slither and MythX can automatically detect potential reentrancy vulnerabilities.
FAQ

Common Misconceptions About Reentrancy Locks

Reentrancy locks, often called mutexes, are a fundamental smart contract security pattern, but several persistent misunderstandings about their implementation and guarantees can lead to critical vulnerabilities.

No, a simple boolean flag is insufficient for preventing reentrancy because it can be bypassed through cross-function or cross-contract attacks. A reentrancy guard must be applied to state-changing functions that call external addresses. An attacker can call a different, unguarded function in your contract that shares state with the guarded function, leading to the same corrupted state updates. The standard practice is to use a modifier like OpenZeppelin's ReentrancyGuard, which uses a nonReentrant modifier that sets and checks a status variable for the entire function execution, protecting against all reentrancy paths.

solidity
// INSECURE - Only protects one path
bool private locked;
function withdraw() public {
    require(!locked, "Reentrant call");
    locked = true;
    (bool success, ) = msg.sender.call{value: address(this).balance}("");
    locked = false; // Too late! State already corrupted.
}
REENTRANCY LOCK

Frequently Asked Questions (FAQ)

Essential questions and answers about reentrancy locks, a fundamental smart contract security mechanism designed to prevent a specific class of critical vulnerabilities.

A reentrancy lock (often called a mutex or non-reentrant modifier) is a smart contract guard that prevents a function from being called recursively before its initial execution completes. It works by setting a boolean state variable (e.g., locked) to true at the start of a function and to false at the end. If a malicious contract attempts to re-enter the function via a callback, the check require(!locked, "Reentrant call detected") will cause the transaction to revert, blocking the attack. This simple pattern is the basis for OpenZeppelin's widely-used ReentrancyGuard contract.

solidity
// Simplified ReentrancyGuard Logic
bool private locked;

modifier nonReentrant() {
    require(!locked, "ReentrancyGuard: reentrant call");
    locked = true;
    _;
    locked = false;
}
ENQUIRY

Get In Touch
today.

Our experts will offer a free quote and a 30min call to discuss your project.

NDA Protected
24h Response
Directly to Engineering Team
10+
Protocols Shipped
$20M+
TVL Overall
NDA Protected direct pipeline
Reentrancy Lock: Definition & Security Mechanism | ChainScore Glossary