BriVault

First Flight #52
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: high
Valid

Inconsistent Mint Recipient and stakedAsset Mapping Causes Broken Logic

Root + Impact

Description

  • The deposit() function mints ERC4626 shares to msg.sender but records the deposited tokens under stakedAsset[receiver].

  • This creates a logical inconsistency between who holds the vault shares and who owns the recorded assets. It directly breaks functions like joinEvent() that depend on stakedAsset[msg.sender] being non-zero, even when the user actually holds valid shares.

Risk

Likelihood:

  • This issue occurs whenever a depositor provides a receiver different from themselves — an entirely valid use case allowed by the ERC4626 standard.

  • The bug doesn’t require any special timing or permissions; it happens every time a third-party deposit (e.g., depositing for a friend or referral system) is executed.

Impact:

  • Users may lose access to event participation logic that depends on stakedAsset[msg.sender].

  • Can cause failed withdrawals, broken events, and incorrect reward distribution.

Proof of Concept

Explanation

The PoC demonstrates that when msg.sender deposits for another user (receiver),

  • Shares are minted to the depositor (msg.sender)

  • But assets are credited to the receiver (stakedAsset[receiver])

Later, joinEvent() checks stakedAsset[msg.sender] and reverts, because it never got updated for the depositor. This proves broken ownership consistency.

function test_InconsistentMintAndStakeMapping() public {
address alice = address(0xA1);
address bob = address(0xB0);
vm.startPrank(alice);
asset.mint(alice, 100e18);
asset.approve(address(vault), 100e18);
// Alice deposits for Bob
vault.deposit(100e18, bob);
vm.stopPrank();
// Shares minted to Alice, but staked asset stored under Bob
assertEq(vault.balanceOf(alice) > 0, true);
assertEq(vault.stakedAsset(bob), 100e18);
assertEq(vault.stakedAsset(alice), 0);
// Alice tries to join event (will revert)
vm.startPrank(alice);
vm.expectRevert();
vault.joinEvent(0); // fails since stakedAsset[alice] == 0
vm.stopPrank();
}

Recommended Mitigation

Explanation

This change ensures both share minting and asset tracking are tied to the same address (receiver).

  • It preserves ERC4626 compliance

  • Prevents broken participation logic

  • Ensures reward and share accounting remain accurate

function deposit(uint256 assets, address receiver)
public
override
returns (uint256)
{
require(receiver != address(0));
IERC20(asset()).safeTransferFrom(msg.sender, address(this), assets);
uint256 participantShares = _convertToShares(assets);
- _mint(msg.sender, participantShares);
- stakedAsset[receiver] += assets;
+ _mint(receiver, participantShares); // consistent
+ stakedAsset[receiver] += assets; // aligned
emit deposited(receiver, assets);
return participantShares;
}
Updates

Appeal created

bube Lead Judge 19 days ago
Submission Judgement Published
Validated
Assigned finding tags:

Shares Minted to msg.sender Instead of Specified Receiver

Support

FAQs

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

Give us feedback!