veRWA - hassan-truscova's results

Incentivization Primitive for Real World Assets on Canto

General Information

Platform: Code4rena

Start Date: 07/08/2023

Pot Size: $36,500 USDC

Total HM: 11

Participants: 125

Period: 3 days

Judge: alcueca

Total Solo HM: 4

Id: 274

League: ETH

Canto

Findings Distribution

Researcher Performance

Rank: 107/125

Findings: 1

Award: $4.23

QA:
grade-b

🌟 Selected for report: 0

🚀 Solo Findings: 0

Lines of code

https://github.com/code-423n4/2023-08-verwa/blob/main/src/VotingEscrow.sol#L572-L596 https://github.com/code-423n4/2023-08-verwa/blob/main/src/VotingEscrow.sol#L576 https://github.com/code-423n4/2023-08-verwa/blob/main/src/VotingEscrow.sol#L431-L446 https://github.com/code-423n4/2023-08-verwa/blob/main/src/VotingEscrow.sol#L439 https://github.com/code-423n4/2023-08-verwa/blob/main/src/VotingEscrow.sol#L487-L527 https://github.com/code-423n4/2023-08-verwa/blob/main/src/VotingEscrow.sol#L491 https://github.com/code-423n4/2023-08-verwa/blob/main/src/VotingEscrow.sol#L451-L466 https://github.com/code-423n4/2023-08-verwa/blob/main/src/VotingEscrow.sol#L459

Vulnerability details

Impact

VotingEscrow’s balanceOfAt and totalSupplyAt call _findUserBlockEpoch and _findBlockEpoc, respectively, to return their corresponding values for a given block. Because the balance and supply can vary within the same block, these functions can return different values when called on the current block.

VotingEscrow’s balanceOfAt(addr, block) and totalSupplyAt(block) use a binary search to return their values associated with the block:

function _findBlockEpoch(uint256 _block, uint256 _maxEpoch) internal view returns (uint256) { .... if (min >= max) break; uint256 mid = (min + max + 1) / 2; if (pointHistory[mid].blk <= _block) { min = mid; } else { max = mid - 1; } .... } function _findUserBlockEpoch(address _addr, uint256 _block) internal view returns (uint256) { .... if (min >= max) { break; } uint256 mid = (min + max + 1) / 2; if (userPointHistory[_addr][mid].blk <= _block) { min = mid; } else { max = mid - 1; } .... }

If a block is contained in pointHistory, the latest one will be used. Points on the current block can be added indefinitely in pointHistory. As a result, a user calling balanceOfAt or totalSupplyAt on the current block might not receive the latest value.

Proof of Concept

Bob creates a voting contract that relies on balanceOfAt and totalSupplyAt. Eve creates a vote using block.number as a snapshot and corrupts the quorum percentage.

Tools Used

Manual + in-house tool

document that balanceOfAt and totalSupplyAt must not be called on the current block.

Assessed type

Invalid Validation

#0 - c4-pre-sort

2023-08-12T07:55:30Z

141345 marked the issue as primary issue

#1 - c4-sponsor

2023-08-16T13:53:54Z

OpenCoreCH marked the issue as sponsor acknowledged

#2 - c4-sponsor

2023-08-16T13:54:01Z

OpenCoreCH marked the issue as disagree with severity

#3 - OpenCoreCH

2023-08-16T13:55:53Z

Documenting this is a good idea, not sure if the severity is appropriate. Any caller that uses these values should use historic block numbers in any case (because the current block is not finalized yet per definition)

#4 - alcueca

2023-08-24T06:41:03Z

Vulnerability on future contract, valid QA for documentation

#5 - c4-judge

2023-08-24T06:41:13Z

alcueca changed the severity to QA (Quality Assurance)

#6 - c4-judge

2023-08-24T06:41:17Z

alcueca marked the issue as grade-b

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