Core Contracts

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

Missing access control modifiers on BaseGauge functions stake and withdraw denies project admins privilege to limit losses when a vulnerability is discoverd

Summary

BaseGauge functions stake and withdraw do not have the access control modifier whenNotPaused.

Vulnerability Details

The access control modifier whenNotPaused enables to the project admins to block access to the contracts for security reasons. This is useful when it is necessary to protect user funds. Applied to the stake function, this can prevent unwary users from depositing more funds that would put them at risk. However, the modifier is currently missing:

/**
* @notice Stakes tokens in the gauge
* @param amount Amount to stake
*/
function stake(uint256 amount) external nonReentrant updateReward(msg.sender) {
if (amount == 0) revert InvalidAmount();
_totalSupply += amount;
_balances[msg.sender] += amount;
stakingToken.safeTransferFrom(msg.sender, address(this), amount);
emit Staked(msg.sender, amount);
}

Similarly, the withdraw function does not have the modifier whenNotPaused:

/**
* @notice Withdraws staked tokens
* @param amount Amount to withdraw
*/
function withdraw(uint256 amount) external nonReentrant updateReward(msg.sender) {
if (amount == 0) revert InvalidAmount();
if (_balances[msg.sender] < amount) revert InsufficientBalance();
_totalSupply -= amount;
_balances[msg.sender] -= amount;
stakingToken.safeTransfer(msg.sender, amount);
emit Withdrawn(msg.sender, amount);
}

Add this POC to test/unit/core/governance/gauges/BaseGauge.test.js that shows that the stake functon can still be called when the contract has been paused by admin:

describe("Emergency Actions", () => {
beforeEach(async () => {
const paused = true;
await baseGauge.connect(owner).setEmergencyPaused(paused);
expect(await baseGauge.paused()).to.equal(paused);
});
it("should stake", async () => {
await rewardToken.mint(user1.address, ethers.parseEther("1000"));
await rewardToken.connect(user1).approve(await baseGauge.getAddress(), ethers.parseEther("1000"));
await baseGauge.connect(user1).stake(ethers.parseEther("1000"));
});
});

Add this POC to test/unit/core/governance/gauges/BaseGauge.test.js that shows that the withdraw functon can still be called when the contract has been paused by admin

describe("Emergency Actions", () => {
beforeEach(async () => {
const paused = true;
await baseGauge.connect(owner).setEmergencyPaused(paused);
expect(await baseGauge.paused()).to.equal(paused);
});
it("should unstake", async () => {
await rewardToken.mint(user1.address, ethers.parseEther("1000"));
await rewardToken.connect(user1).approve(await baseGauge.getAddress(), ethers.parseEther("1000"));
await baseGauge.connect(user1).stake(ethers.parseEther("1000"));
await baseGauge.connect(user1).withdraw(ethers.parseEther("1000"));
});
});

Impact

Token deposit and withdraw functions that do not have the modifier whenNotPaused prevent project admins from protecting users assets incase of emergency. While it is true that the emergencyWithdraw function exists, this might not be sufficient incase users were in the process of depositing, admin might need to call emergencyWithdraw again which can be front-run by attackers.

Tools Used

Manual review

Recommendations

Add the access control modifier whenNotPaused to the functions stake and withdraw.

Updates

Lead Judging Commences

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

BaseGauge::withdraw, stake, and checkpoint functions lack whenNotPaused modifier, allowing critical state changes even during emergency pause

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

BaseGauge::withdraw, stake, and checkpoint functions lack whenNotPaused modifier, allowing critical state changes even during emergency pause

Support

FAQs

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

Give us feedback!