Lucene search

K
code423n4Code4renaCODE423N4:2023-04-FRANKENCOIN-FINDINGS-ISSUES-930
HistoryApr 19, 2023 - 12:00 a.m.

Challenger incentives can be inflated with external transfers

2023-04-1900:00:00
Code4rena
github.com
4
vulnerability
challenger
inflation
collateral
bidder
reward
undercollateralized
position
contract
eth
zchf
bidding
mitigation
challenge

Lines of code

Vulnerability details

Impact

The function notifyChallengeSucceeded calculates the volume of ZCHF to be repaid, which is then used to calculate the reward for the challenger. The challenger can however artificially inflate this value.

A challenger can start a challenge on an undercollateralized position, but specify the _collateralAmount far higher than the actual collateral available. If the liquidation amount is higher than the collateral amount, the contract scales down the specified amount until it matches the collateral present in the contract. However any user can do external transfers of the collateral to inflate the collateral in the contract.

If the challenger is also a bidder, they can artificially inflate the collateral in the Position and then submit the winning bid. The challenger gets paid all the collateral since they are also the bid winner, and on top of it a reward based on the volume, which is artificially pumped up. Thus under certain conditions, bad actors can claim large reward amounts even for small positions.

Consider the case where there exists 1 ETH collateral, and 1500 ZCHF minted against that position. Price of ETH drops and the position is undercollateralized, thus a challenge is opened by the malicious challenger, but instead of claiming 1 ETH, they claim 10 ETH. the function notifyChallengeSucceeded calculates the end results of the bidding, and calculates the volume.

        uint256 colBal = collateralBalance();
        if (_size > colBal) {
            // tell the caller that a part of the bid needs to be returned to the bidder.
            _bid = _divD18(_mulD18(_bid, colBal), _size);
            _size = colBal;
        }
        uint256 volumeZCHF = _mulD18(price, _size);

Right before closing the bid, the challenger/bid winner can send the contract the extra 9 ETH. This way, the colBal value matches _size, and the volumeZCHF is calculated based on a collateral of 10 ETH, instead of 1 ETH.

This value of volumeZCHF is used to pay out rewards. Thus the challenger is able to secure 10x the rewards for the position.

uint256 reward = (volume * CHALLENGER_REWARD) / 1000_000; // Volume is inflated to 10x

Proof of Concept

The attack can be done in the following steps:

  1. Open challenge on an underwater position but with 10x the collateral amount.
  2. Bid on own position to offset the cost from the next step.
  3. Right before end() is called, send the 9x collateral amount to the contract. Due to winning the bid, all initial costs are repaid, and 10x rewards are paid on top.

Tools Used

Manual Review

Recommended Mitigation Steps

Do not allow challenges with _collateralAmount higher than the actual collateral balance.


The text was updated successfully, but these errors were encountered:

All reactions