Platform: Code4rena
Start Date: 16/01/2024
Pot Size: $80,000 USDC
Total HM: 37
Participants: 178
Period: 14 days
Judge: Picodes
Total Solo HM: 4
Id: 320
League: ETH
Rank: 158/178
Findings: 1
Award: $8.76
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: juancito
Also found by: 0x3b, 0xAlix2, 0xAsen, 0xPluto, 0xpiken, Limbooo, Myrault, PENGUN, Ward, a3yip6, b0g0, falconhoof, gkrastenov, haxatron, israeladelaja, jasonxiale, linmiaomiao, memforvik, miaowu, nonseodion, t0x1c, y4y
8.7582 USDC - $8.76
https://github.com/code-423n4/2024-01-salty/blob/main/src/dao/Proposals.sol#L122
The creation of a confirmation proposal can be blocked because of a front-running attack. The setting of the contract address and updating of the website can be blocked forever.
Attack scenario:
ballotName = setContract:priceFeed1
where contractName = priceFeed1
ballotMinimumEndTime
is passed.DAO
contract to try to call the finalizeBallot
function.ballotName = setContract:priceFeed1_confirm
where contractName = priceFeed1_confirm
. Here, openBallotsByName[ballotName]
is equal to the new ballotID
.createConfirmationProposal
function is reached where the _possiblyCreateProposal
function is called. The require statement for openBallotsByName[ballotName] == 0
will not be passed.// Make sure that a proposal of the same name is not already open for the ballot require( openBallotsByName[ballotName] == 0, "Cannot create a proposal similar to a ballot that is still open" );
The ballotName
here would be equal to setContract:priceFeed1_confirm
because the name of confirmation proposal is equal to string.concat(ballot.ballotName, "_confirm")
else if (ballot.ballotType == BallotType.SET_CONTRACT) proposals.createConfirmationProposal( string.concat(ballot.ballotName, "_confirm"), // confirmation proposal name BallotType.CONFIRM_SET_CONTRACT, ballot.address1, "", ballot.description );
As a result, the transaction will revert and can not create a confirmation proposal.
The malicious user can do that endlessly and block the creation of confirmation proposals forever. The only requirement is to have enough staked XSalt
for creating a normal proposal.
Manual Review
Reserve openBallotsByName[ballotName] == 1
, where ballotName = string.concat(ballot.ballotName, "_confirm")
, during the creation of the proposal.
DoS
#0 - c4-judge
2024-02-01T15:56:16Z
Picodes marked the issue as duplicate of #620
#1 - c4-judge
2024-02-19T16:39:27Z
Picodes marked the issue as satisfactory
#2 - c4-judge
2024-02-19T16:39:29Z
Picodes changed the severity to 2 (Med Risk)
#3 - c4-judge
2024-02-19T16:44:05Z
Picodes changed the severity to QA (Quality Assurance)
#4 - c4-judge
2024-02-19T16:44:35Z
This previously downgraded issue has been upgraded by Picodes
#5 - J4X-98
2024-02-22T08:31:53Z
Hey @Picodes,
thanks for reviewing the submission. I would like to add, that this is a duplicate of #980. Both exploit the exactly same issue of appending "setContract:pricefeed1 + _confirm" to the contract name and block other proposals that way.
#6 - othernet-global
2024-02-23T03:22:09Z
confirm_ is now prepended to automatic confirmation ballots form setWebsiteURL and setContract proposals.
https://github.com/othernet-global/salty-io/commit/5aa1bc1ddadd67cd875de932633948af25ff8957
#7 - c4-judge
2024-02-28T10:21:13Z
Picodes marked the issue as not a duplicate
#8 - c4-judge
2024-02-28T10:21:34Z
Picodes marked the issue as duplicate of #620