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

Data Overwrite Vulnerability in InheritanceManager's Protocol Interaction Storage

Finding description and impact

The InheritanceManager contract contains a vulnerability in the contractInteractions function that affects the historic storage of interactions with external protocols. The core issue stems from how the contract stores interaction data in a mapping, where subsequent interactions with the same target address overwrite previous ones rather than preserving the history.

The impact is that:

  • Beneficiaries lose visibility into historical interactions with the same protocol/contract

  • Only the most recent interaction with each target contract is recorded

  • This defeats the stated purpose of making "it clear to beneficiaries where to look for funds outside this contract"

  • Important transaction data could be permanently lost if overwritten

Proof of Concept

The following code segment demonstrates the vulnerability:

mapping(address protocol => bytes) interactions;
function contractInteractions(address _target, bytes calldata _payload, uint256 _value, bool _storeTarget)
external
nonReentrant
onlyOwner
{
(bool success, bytes memory data) = _target.call{value: _value}(_payload);
require(success, "interaction failed");
if (_storeTarget) {
interactions[_target] = data; // Overwrites previous data for the same target
}
}

Consider a scenario where the owner makes multiple deposits to Aave:

  1. Owner deposits 10 ETH to Aave lending pool and stores the interaction

  2. Later, owner deposits another 5 ETH to the same Aave lending pool address

  3. The second interaction overwrites the data from the first interaction

  4. When beneficiaries inherit the contract, they only see evidence of the 5 ETH deposit, potentially losing track of the 10 ETH deposit

Recommended mitigation steps

To fix this issue:

Store an array of interactions per target

// Change mapping to store arrays of bytes
mapping(address protocol => bytes[]) interactions;
function contractInteractions(address _target, bytes calldata _payload, uint256 _value, bool _storeTarget)
external
nonReentrant
onlyOwner
{
(bool success, bytes memory data) = _target.call{value: _value}(_payload);
require(success, "interaction failed");
if (_storeTarget) {
interactions[_target].push(data); // Store in array instead of overwriting
}
}

Tools Used

  • Manual Code Review

  • Foundry Testing Framework

Updates

Lead Judging Commences

0xtimefliez Lead Judge 6 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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