Skip to content

[Security] WBERAStakerVault: completeWithdrawal(bool, uint256) has no caller ownership check #31

@sailorpepe

Description

@sailorpepe

Summary

completeWithdrawal(bool isNative, uint256 requestId) allows any address to complete any user's ERC721-based withdrawal request. The underlying _burnWithdrawalRequest in WBERAStakerVaultWithdrawalRequest calls _burn(requestId) which does not verify the caller is the NFT owner.

Impact

Low — No fund theft is possible because assets are sent to request.receiver (set at queue time, not controlled by the caller). However:

  • An attacker can force-complete someone else's withdrawal before the user is ready
  • The attacker chooses the isNative flag, potentially sending native BERA instead of WBERA (or vice versa)

Note: cancelQueuedWithdrawal correctly checks NFT ownership (line 240), but completeWithdrawal does not.

Affected Code

Compare with cancelQueuedWithdrawal which does check ownership:

if (msg.sender != IERC721(address(withdrawalRequests721)).ownerOf(requestId)) {
    OnlyNFTOwnerAllowed.selector.revertWith();
}

Recommended Fix

Add the same ownership check to completeWithdrawal:

function completeWithdrawal(bool isNative, uint256 requestId) external nonReentrant whenNotPaused {
    if (msg.sender != IERC721(address(withdrawalRequests721)).ownerOf(requestId)) {
        OnlyNFTOwnerAllowed.selector.revertWith();
    }
    _completeWithdrawal(isNative, requestId);
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions