Reentrancy Attack: What Is a Reentrancy Attack in Crypto?A reentrancy attack is a smart contract exploit where an external contract calls back into a vulnerable contract before the first function call has finished.In crReentrancy Attack: What Is a Reentrancy Attack in Crypto?A reentrancy attack is a smart contract exploit where an external contract calls back into a vulnerable contract before the first function call has finished.In cr

Reentrancy Attack

2026/08/07 17:45
#Advanced

What Is a Reentrancy Attack in Crypto?

A reentrancy attack is a smart contract exploit where an external contract calls back into a vulnerable contract before the first function call has finished.

In crypto, this attack usually targets smart contracts that hold funds, track balances, process withdrawals, calculate rewards, manage vault shares, or interact with other contracts.

The core problem is that the vulnerable contract gives control to another contract before it has finished updating its own internal state.

If the attacker can re-enter the contract during that unfinished state, the attacker may repeat an action that should have been allowed only once.

A common example is a withdrawal function that sends crypto to a user before reducing the user’s recorded balance.

If the recipient is a malicious contract, it can use its fallback or callback logic to call the withdrawal function again before the balance is updated.

This can allow the attacker to withdraw more than the amount they are entitled to receive.

The OWASP Smart Contract Top 10 2026 reentrancy page defines reentrancy as a situation where a contract performs an external call and the callee calls back into the original contract before state has been fully updated.

Reentrancy is one of the most famous smart contract vulnerabilities because it directly attacks the trust model of on-chain accounting.

It is especially dangerous in decentralized finance because smart contracts often manage large pools of liquidity and depend on other contracts for swaps, collateral, rewards, or price data.

How a Reentrancy Attack Works

A reentrancy attack starts when a vulnerable smart contract makes an external call to another contract or address.

That external call may send native cryptocurrency, transfer tokens, call a hook, request a callback, execute a strategy, or interact with another protocol.

When the vulnerable contract makes that call, it temporarily gives the receiving contract a chance to run its own code.

If the receiving contract is controlled by an attacker, the attacker can use that moment to call back into the vulnerable contract.

The vulnerable contract may still have old state values because it has not yet updated balances, debt, shares, reward indexes, or lock flags.

The attacker can exploit those old values to repeat a withdrawal, claim rewards twice, borrow more than allowed, or manipulate a calculation.

The attack continues until the vulnerable contract runs out of funds, the transaction runs out of gas, or a protection mechanism stops the repeated calls.

The Solidity documentation on external calls warns that interacting with another contract hands over control to that contract and that the called contract may call back into the original contract before the first call returns.

This warning is the foundation of reentrancy defense.

Any external call should be treated as a possible point where the contract’s assumptions can be broken.

Simple Reentrancy Example

Imagine a lending contract that records each user’s deposit balance.

A user deposits 10 ETH into the contract.

The contract records that the user has a balance of 10 ETH.

The user later calls a withdraw function to receive the 10 ETH back.

A safe contract would reduce the user’s balance to zero before sending the ETH.

A vulnerable contract sends the ETH first and updates the balance afterward.

If the user is actually a malicious contract, its receive function can run when the ETH is sent.

That receive function can immediately call withdraw again while the vulnerable contract still thinks the user has 10 ETH.

The same withdrawal may happen again and again inside one transaction.

This is why the ordering of smart contract logic matters so much.

In traditional software, a small ordering bug may cause a normal accounting error.

In a smart contract that holds crypto assets, the same ordering bug can become a direct path to asset theft.

Why Reentrancy Attacks Are Dangerous

Reentrancy attacks are dangerous because smart contracts often control assets that cannot easily be recovered after an exploit.

Public blockchains are designed to execute valid transactions and preserve their history.

If a malicious transaction follows the rules of the blockchain but exploits a contract bug, reversing the damage is usually difficult.

The Ethereum.org smart contract security guide explains that deployed smart contract code is usually hard to change and that stolen assets are difficult to recover because of blockchain immutability.

This makes prevention much more important than after-the-fact repair.

A reentrancy bug can drain liquidity pools, vaults, bridges, staking systems, NFT marketplaces, reward contracts, and lending protocols.

It can also damage user trust even if the stolen amount is later recovered.

In crypto, smart contract risk is not only a developer problem.

It can become a user problem, a liquidity problem, a governance problem, and a reputation problem at the same time.

Classic Reentrancy

Classic reentrancy happens when an attacker re-enters the same function that made the external call.

The most common example is a vulnerable withdraw function.

The function checks that a user has a balance, sends funds to the user, and only then updates the balance.

The attacker’s contract receives the funds and calls the same withdraw function again before the balance is reduced.

This creates a loop where the same recorded balance can be used multiple times.

Classic reentrancy is easy to understand, but it is still dangerous because many developers continue to write external-call logic too early.

It is also dangerous because modern contracts often have more complex accounting than a simple deposit and withdrawal mapping.

A vulnerable function may involve shares, debt positions, reward multipliers, vault assets, liquidity tokens, or fee accounting.

Even if the pattern looks different from the classic example, the same core issue can still exist.

Cross-Function Reentrancy

Cross-function reentrancy happens when the attacker re-enters a different function in the same contract.

This is more subtle than classic reentrancy because the attacked function may appear safe when reviewed alone.

For example, one function may start a withdrawal and make an external call.

During that external call, the attacker may call another function that relies on the same balance, share, or permission state.

If the first function has not finished updating state, the second function may see stale information.

This can allow the attacker to claim rewards, transfer shares, borrow assets, or change a position before the first action is complete.

Cross-function reentrancy shows why developers must think about contract-wide invariants instead of only protecting one obvious withdraw function.

A contract invariant is a rule that should remain true before and after every valid operation.

If external calls can temporarily break an invariant, other functions may become attack paths.

Cross-Contract Reentrancy

Cross-contract reentrancy happens when the callback path moves through multiple contracts.

This can happen in DeFi systems where vaults, strategies, routers, token contracts, oracle readers, staking modules, and reward distributors interact with each other.

A vault may call a strategy.

The strategy may call a token or another protocol.

The called contract may trigger a callback that reaches back into the vault or into a related contract that the vault depends on.

The vulnerable state may not be in the same contract that made the first external call.

The Solidity security considerations note that reentrancy is not only caused by Ether transfers and that multi-contract situations must also be considered.

This is important because modern crypto applications are highly composable.

Composability lets protocols connect and build on each other, but it also creates more paths for unexpected callbacks.

Read-Only Reentrancy

Read-only reentrancy happens when a view or read function returns misleading information during an unfinished state transition.

At first, this may sound harmless because view functions do not directly modify state.

However, other contracts may use view functions to calculate prices, shares, collateral values, exchange rates, or reward amounts.

If a callback happens while one contract is in an intermediate state, a view function may return a temporary value that should not be trusted.

An attacker may use that temporary value in another contract that relies on it.

This can create oracle-like manipulation or accounting errors without directly draining the first contract through a normal withdrawal function.

Read-only reentrancy is a reminder that security is not only about whether a function writes to storage.

It is also about whether other contracts can observe incomplete state and make financial decisions based on it.

Hook-Based Reentrancy

Hook-based reentrancy happens when token standards or protocol interfaces intentionally call receiver logic during a transfer or operation.

Some token and NFT standards include receiver hooks so contracts can react when they receive assets.

Flash loan systems also use callbacks so a borrower can use borrowed liquidity and repay within the same transaction.

These hooks are useful, but they also create callback opportunities.

If a contract assumes that a token transfer is a simple action with no external code execution, it may be wrong.

A transfer may trigger receiver logic, operator hooks, or other contract behavior depending on the token standard and implementation.

Developers should review every external token interaction as a possible reentrancy point.

This is especially important for contracts that support many tokens, many vault assets, or many external integrations.

Common Reentrancy Attack Targets

Withdrawal functions are the most common reentrancy target because they often send funds out of a contract.

Vault deposit and withdrawal functions are also common targets because they update share balances and asset accounting.

Lending protocols can be targets because they track collateral, debt, interest, liquidation thresholds, and borrowed balances.

Staking contracts can be targets because they calculate rewards over time and may transfer reward tokens during claims.

NFT marketplaces can be targets because purchases and payouts may trigger token receiver hooks or external royalty logic.

Bridge contracts can be targets because they manage cross-chain messages, asset locks, and release logic.

Governance execution contracts can be targets because they call external contracts while executing proposals.

Flash loan receivers and providers can be targets because their design depends on callbacks.

Any smart contract that sends value or calls untrusted code before finishing internal accounting should be treated as a possible reentrancy target.

The Checks-Effects-Interactions Pattern

The Checks-Effects-Interactions pattern is one of the most important defenses against reentrancy attacks.

Checks means the contract first verifies that the user is allowed to perform the action.

Effects means the contract updates its own internal state before making any external call.

Interactions means the contract performs external calls only after checks and state updates are complete.

For a withdrawal function, the contract should check that the user has a balance, reduce the balance, and only then send funds.

This way, if the recipient tries to re-enter, the contract already reflects the updated balance.

The Solidity Checks-Effects-Interactions documentation describes this pattern as a common way to prevent reentrancy attacks.

This pattern is simple, but it is not optional for contracts that interact with untrusted external code.

Developers should make it a default habit whenever a function changes state and calls outside the contract.

Reentrancy Guards

A reentrancy guard is a lock that prevents a protected function from being entered again before the first call finishes.

In Solidity contracts, this is often implemented with a status variable that marks a function as entered during execution.

If a reentrant call tries to enter the same protected path, the guard rejects it.

The OpenZeppelin Contracts 5.x ReentrancyGuard documentation describes ReentrancyGuard as a module that provides a nonReentrant modifier to prevent nested reentrant calls.

Reentrancy guards are useful because they add a clear safety layer to high-risk functions.

However, a guard is not a replacement for correct accounting.

Developers should still use Checks-Effects-Interactions and review all external calls.

OpenZeppelin also notes that because there is a single nonReentrant guard, functions marked nonReentrant may not call one another directly.

A common workaround is to make the internal logic private and expose separate external entry points protected by nonReentrant.

Transient Storage and Reentrancy Locks

Transient storage is a newer EVM feature that can be used for temporary values that last only during a transaction.

It can be useful for reentrancy locks because a lock does not always need to remain in permanent storage after the call finishes.

The OpenZeppelin ReentrancyGuardTransient documentation describes a transient-storage variant of ReentrancyGuard for chains where EIP-1153 is available.

The Solidity transient storage documentation says using transient storage for reentrancy locks that are cleared at the end of the call frame is safe.

This does not mean every contract should automatically use transient storage.

Developers must confirm that the target chain supports the required feature and that the lock is cleared correctly.

A poorly managed lock can break composability or make the contract difficult to use in complex transactions.

The best choice depends on the target blockchain, compiler version, library version, upgrade pattern, and audit requirements.

Why Transfer and Send Are Not Complete Defenses

Older Solidity guidance often treated limited-gas transfers as a practical reentrancy mitigation.

Modern guidance is more careful because gas costs and EVM behavior can change over time.

The Solidity address members documentation warns that send and transfer are deprecated and recommends other means to protect against reentrancy.

This matters because relying only on a gas stipend can create a false sense of security.

A contract should be safe because its state logic is correct, not because it assumes a recipient will not have enough gas to do anything dangerous.

The safer approach is to update state before external calls, use reentrancy guards where appropriate, check return values, and design withdrawal flows carefully.

Developers should also review old code that still depends on transfer or send as the main protection against reentrancy.

Crypto security practices change as protocol rules, gas costs, and common attack techniques evolve.

Pull Payments as a Defense

A pull payment pattern lets recipients withdraw funds themselves instead of forcing a contract to push funds during another operation.

This reduces risk because the contract can record a payment owed and let the recipient claim it in a separate step.

For example, a marketplace may record seller proceeds instead of sending funds to the seller inside the buyer’s purchase transaction.

The seller later calls a withdraw function to claim the funds.

This pattern can limit the damage caused by a malicious recipient that rejects payments or tries to re-enter during a payout.

The OpenZeppelin security utilities documentation describes PullPayment as a pattern that can help avoid reentrancy attacks.

Pull payments are not perfect for every design because they may add extra user steps.

However, they can be very useful when many users or contracts need to receive payments from the same system.

Emergency Pause Controls

An emergency pause control allows authorized accounts or governance systems to pause sensitive functions during an incident.

This can help limit damage if suspicious behavior or a potential reentrancy exploit is detected.

A pause function may stop withdrawals, deposits, reward claims, new loans, or other risky actions while the team investigates.

OpenZeppelin lists Pausable as a common emergency response mechanism that can pause functionality while remediation is pending.

A pause system should be designed carefully because it introduces governance and centralization trade-offs.

If the pause authority is too powerful, users may worry about censorship or misuse.

If the pause authority is too weak or too slow, it may not help during an active exploit.

For high-value crypto protocols, emergency response planning should be part of security design from the beginning.

How Developers Can Detect Reentrancy Risk

Developers can detect reentrancy risk by reviewing every external call in the contract.

External calls include native coin transfers, token transfers, low-level calls, interface calls, flash loan callbacks, NFT receiver hooks, and calls to protocol modules.

For each external call, developers should ask whether internal state has already been updated.

They should also ask whether another function can be called during the external call and observe stale state.

They should review whether multiple contracts share assumptions that could be broken by a callback.

They should test malicious receiver contracts that try to call back into every public and external function.

They should use static analysis, fuzz testing, unit testing, invariant testing, and manual review together.

The Solidity SMTChecker documentation includes reentrancy properties as one category of behavior that can be analyzed around external calls to unknown code.

No single tool can guarantee that a contract is safe.

Reentrancy detection works best when automated tools are combined with experienced security review.

How Users Can Think About Reentrancy Risk

Most users cannot fully audit a smart contract before using it.

However, users can still reduce risk by looking for signs of strong security practice.

A protocol should provide clear documentation about audits, bug bounty programs, emergency controls, upgrade permissions, and risk disclosures.

Users should be careful with new contracts that hold large value but have little public review.

Users should also be careful when a protocol offers unusually high yields without explaining the source of returns and smart contract risks.

Reentrancy risk can exist even when a user interface looks polished and professional.

A good interface does not prove that the underlying contract logic is safe.

Users should avoid depositing more than they can afford to lose into unaudited or experimental contracts.

They should also understand that audits reduce risk but do not remove it completely.

Reentrancy and DeFi Composability

DeFi composability means smart contracts can connect with each other like financial building blocks.

This is one of crypto’s most powerful features because it allows wallets, vaults, lending markets, swaps, derivatives, staking systems, and governance tools to interact.

However, composability also increases reentrancy risk because one transaction can pass through many contracts.

A safe-looking operation in one contract may trigger complex behavior in another contract.

A callback may reach a third contract that changes a value the first contract depends on.

A price, share value, or balance may be read during a temporary state that was never meant to be externally observed.

This is why modern reentrancy analysis must include the full interaction path.

Developers should not review each contract as if it exists alone.

They should review how contracts behave when combined with routers, tokens, vaults, flash loans, and external strategies.

Reentrancy and Flash Loans

Flash loans can make reentrancy attacks more powerful because they allow attackers to access large temporary liquidity within one transaction.

A flash loan by itself is not a reentrancy attack.

It is a tool that can be used for legitimate arbitrage, refinancing, liquidation, and capital-efficient operations.

However, if a vulnerable contract can be manipulated within one transaction, a flash loan may give the attacker enough capital to make the exploit profitable.

Flash loan callbacks also require careful design because callback-based systems intentionally hand control to another contract.

Developers should treat every callback as an untrusted external call unless there is a strong reason not to do so.

They should update state before callbacks when possible and verify final repayment, balances, and invariants after the callback returns.

Flash loan integrations should be tested with malicious borrower contracts, not only with normal borrower examples.

Reentrancy and Upgradeable Contracts

Upgradeable contracts need special care when using reentrancy protections.

An upgradeable proxy separates user-facing storage from implementation logic.

If a reentrancy guard uses storage, developers must ensure that storage layout is correct and compatible across upgrades.

Changing storage layout incorrectly can break the guard or corrupt important state variables.

Developers should use upgradeable-compatible libraries when building upgradeable contracts.

They should also test upgrades against previous contract states rather than only testing fresh deployments.

A contract may be safe in version one and become vulnerable after a later upgrade changes call order or adds a new external integration.

Upgrade reviews should include reentrancy analysis for every new external call.

Governance or admin systems that execute upgrades should also have delay, review, and emergency controls when the protocol holds meaningful value.

Best Practices to Prevent Reentrancy Attacks

Update internal state before making external calls.

Use the Checks-Effects-Interactions pattern for withdrawals, claims, transfers, swaps, and accounting changes.

Apply a reentrancy guard to high-risk external entry points.

Do not assume token transfers are always simple because some token standards and implementations can trigger hooks or callbacks.

Do not rely only on transfer or send gas limits as a reentrancy defense.

Use pull payment patterns when direct payouts create unnecessary risk.

Review cross-function and cross-contract reentrancy, not only classic same-function reentrancy.

Test with malicious receiver contracts that try to re-enter during every external call.

Use invariant testing to confirm that total balances, shares, debt, and reserves remain correct across complex interactions.

Include emergency pause and incident response plans for high-value systems.

Get independent security review before deploying contracts that hold user funds.

Keep dependencies updated and check library migration notes before changing major versions.

Common Developer Mistakes

One common mistake is updating balances after sending funds.

Another common mistake is protecting only the withdraw function while leaving related functions open to cross-function reentrancy.

Another common mistake is assuming that a token transfer cannot execute external code.

Another common mistake is using a reentrancy guard on one contract while ignoring calls into related contracts that share accounting assumptions.

Another common mistake is relying on old transfer and send assumptions instead of designing state logic correctly.

Another common mistake is adding a new external integration during an upgrade without re-checking the entire call path.

Another common mistake is treating view functions as harmless even when other contracts depend on their values during complex transactions.

Another common mistake is forgetting that malicious contracts can deliberately behave differently from normal users.

Security testing should assume hostile behavior, not only normal interface usage.

FAQ

What does reentrancy attack mean?

A reentrancy attack means a malicious contract calls back into a vulnerable smart contract before the first function call finishes and before state is safely updated.

Why is reentrancy dangerous in crypto?

Reentrancy is dangerous because it can let attackers drain funds, claim rewards multiple times, manipulate accounting, or break contract assumptions in one transaction.

No, Solidity documentation warns that reentrancy is not only related to Ether transfers because any external contract call can create callback risk.

What is the best-known defense against reentrancy?

The Checks-Effects-Interactions pattern is one of the best-known defenses because it updates contract state before making external calls.

What is ReentrancyGuard?

ReentrancyGuard is a smart contract utility that provides a nonReentrant modifier to prevent nested calls into protected functions.

Can ReentrancyGuard prevent every reentrancy bug?

No, ReentrancyGuard helps protect certain entry points, but developers still need correct accounting, safe call ordering, and cross-contract review.

What is cross-function reentrancy?

Cross-function reentrancy happens when an attacker re-enters a different function in the same contract while the first function is still unfinished.

What is read-only reentrancy?

Read-only reentrancy happens when a view function returns misleading temporary state during an unfinished operation and another contract relies on that value.

Can token transfers cause reentrancy?

Yes, some token standards and token implementations can trigger hooks or callbacks, so token transfers should be reviewed as possible external calls.

Should users avoid all smart contracts because of reentrancy?

No, users do not need to avoid all smart contracts, but they should prefer protocols with strong audits, clear documentation, active monitoring, and responsible risk controls.

Conclusion

A reentrancy attack is a smart contract exploit that takes advantage of unfinished state during an external call.

The attacker re-enters the vulnerable contract before the first call is complete and uses stale accounting to gain more value than allowed.

Although the classic example is a repeated withdrawal, modern reentrancy can also involve cross-function calls, cross-contract flows, read-only state, token hooks, flash loan callbacks, and DeFi composability.

The main lesson is that every external call should be treated as a possible handoff of control to untrusted code.

Developers can reduce reentrancy risk by following Checks-Effects-Interactions, using reentrancy guards, avoiding unsafe payout patterns, testing malicious callbacks, and reviewing full contract interaction paths.

Users can reduce exposure by choosing protocols that take smart contract security seriously and by avoiding unaudited systems that hold significant value.

Reentrancy remains a major crypto security concept because it turns a small logic-ordering mistake into a potentially severe financial exploit.

Understanding reentrancy helps developers build safer contracts and helps users understand why smart contract audits, security patterns, and risk controls matter.

您可能也喜欢

波动性爆发

「波动性爆发」是指金融市场、资产或指数的波动性突然显著增加,通常由不可预见的事件或市场情绪变化所驱动。这种突如其来的增加会导致价格大幅波动和交易量激增,从而影响投资者和交易者的风险和机会。 了解波动性爆发 波动性是衡量特定证券或市场指数收益分散程度的统计指标,显示资产价格在特定期间内的波动幅度。当这种波动超出正常水平时,就会发生波动性爆发,这通常是对意外新闻或经济事件的反应。这些事件可能包括地缘政
2025/12/23 18:42

反恐融资(CTF)

反恐怖主义融资(CTF)是指旨在发现、预防和打击恐怖主义活动资金支持的法律、法规和活动。这包括监控和监管资金流动、在金融机构内部实施合规计划,以及执行旨在遏制恐怖主义融资的国际制裁和法规。 反恐融资在各领域的重要性 反恐融资在包括银行业、科技和国际贸易在内的各个领域都至关重要。在金融领域,强而有力的反恐融资措施可确保银行和其他金融机构不会被恐怖组织利用为其活动提供资金。这不仅有助于维护金融体系的完
2025/12/23 18:42

监管差距

「监管缺口」指的是缺乏或不足以应对技术、市场或其他领域中新兴或不断发展的监管框架或指南。当创新速度超过相关法律法规的发展速度时,这种缺口往往就会出现,导致新技术或商业实践要么受到部分监管,要么完全不受监管。 监管缺口范例 加密货币领域就是一个典型的监管缺口案例。随着比特币和以太币等数位货币的普及,监管机构难以将这些新型资产纳入传统的金融监管框架。这导致加密货币的法律地位存在不确定性,且在不同司法管
2025/12/23 18:42