Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: high
Valid

Misaligned Transient Storage in nonReentrant Modifier of InheritanceManager Contract

Summary

The InheritanceManager contract employs a nonReentrant modifier intended to safeguard against reentrancy attacks. However, a critical flaw in its implementation undermines this protection. Specifically, the modifier checks a different transient storage slot than the one it modifies to set the lock, rendering the reentrancy safeguard ineffective. This vulnerability exposes the contract to reentrancy attacks, despite the presence of the modifier, jeopardizing its security and the assets it manages.

Vulnerability Details

The nonReentrant modifier utilizes transient storage via EIP-1153’s tload and tstore opcodes—to implement a lock mechanism that prevents reentrant calls.
The modifier’s code is as follows:

modifier nonReentrant() {
assembly {
if tload(1) { revert(0, 0) }
tstore(0, 1)
}
_;
assembly {
tstore(0, 0)
}
}

Breakdown of the vulnerability

  • Reentrancy Check:The modifier uses tload(1) to check transient storage slot 1. If the value is non-zero, it reverts, assuming the function is already in execution.

  • Lock Setting: It sets transient storage slot 0 to 1 using tstore(0, 1) before the function executes.

  • Lock Clearing: After execution, it resets slot 0 to 0 with tstore(0, 0).

The critical issue arises from the mismatch between the slot checked (slot 1) and the slot used for locking (slot 0):
The reentrancy check (tload(1)) examines slot 1, which is never modified by the modifier.

  • The lock is set and cleared in slot 0, meaning the check does not reflect the actual lock status.

  • Consequently, a reentrant call bypasses the check because slot 1 remains 0, even when slot 0 is locked (set to 1).

Example Scenario

Consider the following sequence:

  1. Initial Call:

  • tload(1) reads slot 1, which is 0 (default value).

  • tstore(0, 1) sets slot 0 to 1, locking the function.

  • Execution proceeds.

  1. Reentrant Call (triggered before the first call completes):

  • tload(1) again reads slot 1, which remains 0 (unaffected by the prior tstore(0, 1)).

  • The check passes, allowing the reentrant call to proceed despite slot 0 being locked.

This flaw nullifies the nonReentrant modifier’s intended protection, as it fails to detect and prevent reentrant calls.

Impact

The ineffective nonReentrant modifier leaves the InheritanceManager contract vulnerable to reentrancy attacks, with severe potential consequences, including:

  • Fund Draining: An attacker could exploit functions like sendETH or contractInteractions to repeatedly withdraw ETH or tokens, draining the contract’s balances.

  • State Corruption: Reentrancy could lead to inconsistent state changes, especially in functions modifying critical variables, undermining the contract’s logic.

  • Loss of Assets: Assets intended for inheritance distribution could be stolen, defeating the contract’s purpose.

Since the nonReentrant modifier is applied to asset-handling functions (e.g., sendERC20, sendETH, contractInteractions), this vulnerability poses a significant security risk.

Tools Used

Manual Review

Recommendations

To address this vulnerability, the following remediation steps are recommended:

  • Align Slot Usage
    Modify the nonReentrant modifier to use the same transient storage slot for both checking and locking. For example:

modifier nonReentrant() {
assembly {
if tload(0) { revert(0, 0) }
tstore(0, 1)
}
_;
assembly {
tstore(0, 0)
}
}

This ensures the check and lock operate on the same slot (e.g., slot 0), correctly preventing reentrancy.

  • Adopt a Standard Library

Replace the custom nonReentrant modifier with OpenZeppelin’s ReentrancyGuard, a well-tested and widely trusted solution:

import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
contract InheritanceManager is Trustee, ReentrancyGuard {
function sendERC20(address _tokenAddress, uint256 _amount, address _to)
external
nonReentrant
onlyOwner
{
// Function logic
}
}

This leverages a proven implementation, reducing the risk of custom errors.

Updates

Lead Judging Commences

0xtimefliez Lead Judge 10 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Wrong value in nonReentrant modifier

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!