Summary
WBERAStakerVault inherits ERC4626Upgradeable without overriding _decimalsOffset() (defaults to 0). Combined with the permissionless receiveRewards(uint256) function, this enables the classic ERC4626 share price inflation attack against first depositors.
Root Cause
- No virtual shares:
_decimalsOffset() is not overridden, so no virtual shares protection exists.
- Permissionless donation:
receiveRewards(uint256) has no access control — anyone can donate WBERA to inflate totalAssets().
Attack Path
- Attacker is the first depositor — deposits 1 wei WBERA → receives 1 share
- Attacker calls
receiveRewards(1e18) → donates 1e18 WBERA directly to vault
- Share price =
totalAssets / totalShares = (1e18 + 1) / 1 ≈ 1e18 per share
- Victim deposits 1.99e18 WBERA →
previewDeposit = 1.99e18 * 1 / (1e18+1) = 1 share (truncated)
- Attacker now owns 50% of vault (1 of 2 shares) but funded ~1e18 of ~3e18 total
- Attacker withdraws → receives ~1.5e18, profiting ~0.5e18 at victim's expense
Existing Mitigation
The NatSpec mentions "Inflation Attack Protection: Initial deposit mechanism" — this is an operational mitigation (governance deposits first), but it is not enforced in code. If governance forgets or the vault is redeployed without the initial deposit, the attack surface exists.
Recommended Fix
Override _decimalsOffset() to add code-level virtual shares protection:
function _decimalsOffset() internal pure override returns (uint8) {
return 3; // creates 1000 virtual shares per asset unit
}
Alternatively or additionally, add access control to receiveRewards:
function receiveRewards(uint256 amount) external onlyRole(MANAGER_ROLE) {
WBERA.safeTransferFrom(msg.sender, address(this), amount);
emit RewardsReceived(msg.sender, amount, totalAssets());
}
References
Severity
Medium — Exploitable only before initial governance deposit. Operational mitigation exists but is not code-enforced.
Summary
WBERAStakerVaultinheritsERC4626Upgradeablewithout overriding_decimalsOffset()(defaults to 0). Combined with the permissionlessreceiveRewards(uint256)function, this enables the classic ERC4626 share price inflation attack against first depositors.Root Cause
_decimalsOffset()is not overridden, so no virtual shares protection exists.receiveRewards(uint256)has no access control — anyone can donate WBERA to inflatetotalAssets().Attack Path
receiveRewards(1e18)→ donates 1e18 WBERA directly to vaulttotalAssets / totalShares=(1e18 + 1) / 1≈ 1e18 per sharepreviewDeposit=1.99e18 * 1 / (1e18+1)= 1 share (truncated)Existing Mitigation
The NatSpec mentions "Inflation Attack Protection: Initial deposit mechanism" — this is an operational mitigation (governance deposits first), but it is not enforced in code. If governance forgets or the vault is redeployed without the initial deposit, the attack surface exists.
Recommended Fix
Override
_decimalsOffset()to add code-level virtual shares protection:Alternatively or additionally, add access control to
receiveRewards:References
Severity
Medium — Exploitable only before initial governance deposit. Operational mitigation exists but is not code-enforced.