Behodler contest - CertoraInc's results

Ethereum liquidity protocol powered by token bonding curves.

General Information

Platform: Code4rena

Start Date: 27/01/2022

Pot Size: $90,000 USDC

Total HM: 21

Participants: 33

Period: 7 days

Judge: Jack the Pug

Total Solo HM: 14

Id: 78

League: ETH

Behodler

Findings Distribution

Researcher Performance

Rank: 5/33

Findings: 5

Award: $6,637.35

🌟 Selected for report: 9

🚀 Solo Findings: 2

Findings Information

🌟 Selected for report: CertoraInc

Labels

bug
2 (Med Risk)
resolved
sponsor confirmed

Awards

1987.8596 USDC - $1,987.86

External Links

Handle

CertoraInc

Vulnerability details

LimboDAO.sol (updateCurrentProposal() modifier and makeProposal() function)

The LimboDAO contract has a variable that indicates the current proposal - every time there can be only one proposal. The only way a proposal can be done and a new proposal can be registered is to finish the previous proposal by either accepting it and executing it or by rejecting it. If a proposal that can't succeed, like for example an UpdateMultipleSoulConfigProposal proposal that has too much tokens and not enough gas, will stuck the system if it will be accepted. Thats because its time will pass - the users won't be able to vote anymore (because the vote function will revert), and the proposal can't be executed - the execute function will revert. So the proposal won't be able to be done and the system will be stuck because new proposal won't be able to be registered.

When trying to call the executeCurrentProposal() function that activates the updateCurrentProposal() modifier, the modifier will check the balance of fate, it will see that it's positive and will call currentProposalState.proposal.orchestrateExecute() to execute the proposal. the proposal will revert and cancel it all (leaving the proposal as the current proposal with voting state).

When trying to call makeProposal() function to make a new proposal it will revert because the current proposal is not equal to address(0).

To sum up, the system can get to a "stuck" state if a bad proposal (proposal that can't be executed) is accepted.

#0 - gititGoro

2022-02-03T22:05:58Z

I'm so glad someone finally noticed this. So many issues logged skirted around this issue. A lot of issues were logged about adding too may token to the updateMultipleSoulProposal but the crux of the matter is that the proposal.execute() should be replaced with a call that returns a success boolean so that the DAO doesn't get stuck on broken proposals. Congratulations on spotting this.

#1 - jack-the-pug

2022-02-16T12:49:46Z

This is a good one, but I'm still going to downgrade this to medium as there is no fund at risk afaics.

#2 - gititGoro

2022-03-02T03:35:31Z

@jack-the-pug There is a funds risk. Limbo can be paused via flash governance. When paused, funds can't be withdrawn. The only way to unpause is with a proposal. If the DAO gets jammed up with a broken proposal contract then an attacker can pause Limbo and all staked funds will be locked permanently.

#3 - jack-the-pug

2022-03-02T04:08:14Z

@jack-the-pug There is a funds risk. Limbo can be paused via flash governance. When paused, funds can't be withdrawn. The only way to unpause is with a proposal. If the DAO gets jammed up with a broken proposal contract then an attacker can pause Limbo and all staked funds will be locked permanently.

Yeah, I agree that funds can be at risk indirectly, like the vector you described above, but only when the warden made a clear and persuasive presentation about how the funds can be at risk, then it can be a High.

Furthermore, this attack vector requires the community to misbehave or at least be imprudent, to pass a malicious proposal, which already lowers the severity of it.

#4 - gititGoro

2022-05-31T22:17:04Z

Findings Information

🌟 Selected for report: CertoraInc

Labels

bug
2 (Med Risk)
disagree with severity
resolved
sponsor confirmed

Awards

1987.8596 USDC - $1,987.86

External Links

Handle

CertoraInc

Vulnerability details

Flan.sol (safeTransfer() function)

The flan contract must have balance (and must have more flan then we want to transfer) in order to allow flan transfers. If it doesn't have any balance, the safeTransfer, which is the only way to transfer flan, will call _transfer() function with amount = 0. It should check address(msg.sender)'s balance instead of address(this)'s balance.

function safeTransfer(address _to, uint256 _amount) external {
       uint256 flanBal = balanceOf(address(this)); // the problem is in this line
       uint256 flanToTransfer = _amount > flanBal ? flanBal : _amount;
       _transfer(_msgSender(), _to, flanToTransfer);
   }

#0 - jack-the-pug

2022-02-16T12:52:51Z

downgrade to medium as there is no fund at risk.

Findings Information

🌟 Selected for report: CertoraInc

Also found by: Randyyy

Labels

bug
question
2 (Med Risk)
resolved
sponsor confirmed

Awards

894.5368 USDC - $894.54

External Links

Handle

CertoraInc

Vulnerability details

Limbo.sol (stake() function)

if a user has a pending reward and he call the stake function with amount = 0, he won't be able to get his reward (he won't get the reward, and the reward debt will cover the reward)

that's happening because the reward calculation is done only if the staked amount (given as a parameter) is greater than 0, and it updates the reward debt also if the amount is 0, so the reward debt will be updated without the user will be able to get his reward

#0 - gititGoro

2022-02-03T21:24:49Z

Good catch! I'd be interested in your mitigation step being provided.

To me, it looks like the simplest solution is just to remove that if statement. Users who stake zero will pay unnecessary gas costs but the contract shouldn't have to optimise gas consumption for undesired behaviour.

#1 - jack-the-pug

2022-02-27T08:11:25Z

Upgraded to Med as users can lose their rewards.

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter