Skip to content

Latest commit

 

History

History
92 lines (66 loc) · 3.98 KB

078.md

File metadata and controls

92 lines (66 loc) · 3.98 KB

Smooth Sapphire Barbel

Medium

DebitaIncentives::incentivizePair Unsafe Use of ERC20.transferFrom Could Artificially Inflate Balance

Summary

The incentivizePair function in the DebitaIncentives contract allows users to bribe a principal-collateral pair in order to incentivize liquidity. However, a vulnerability exists in the current implementation. Specifically, when tokens are transferred to the DebitaIncentives contract, the contract does not enforce a whitelist on the tokens, meaning any ERC20 token could be used. Additionally, the contract calls transferFrom without checking the return value. This creates a potential attack vector, as a malicious user could use a token that returns false on failed transfers to incentivize a pair, causing the contract state to be incorrectly updated, even though the tokens were never actually transferred. Importantly, the only token checked against the whitelist is the principal token, leaving the incentive token unchecked. This issue could lead to the loss of funds.

   function incentivizePair(
        address[] memory principles,
        address[] memory incentiveToken,
        bool[] memory lendIncentivize,
        uint[] memory amounts,
        uint[] memory epochs
    ) public {
        require(
            principles.length == incentiveToken.length &&
                incentiveToken.length == lendIncentivize.length &&
                lendIncentivize.length == amounts.length &&
                amounts.length == epochs.length,
            "Invalid input"
        );

        for (uint i; i < principles.length; i++) {
            uint epoch = epochs[i];
            address principle = principles[i];
            address incentivizeToken = incentiveToken[i];
            uint amount = amounts[i];

            require(epoch > currentEpoch(), "Epoch already started");
@>          require(isPrincipleWhitelisted[principle], "Not whitelisted");
// @> Only the principle is validated against the whitelist.

            ...

            // transfer the tokens
@>          IERC20(incentivizeToken).transferFrom(
                msg.sender,
                address(this),
                amount
            );
// @> In case the transferFrom returns false, the tx should revert

            // add the amount to the total amount of incentives
            if (lendIncentivize[i]) {
@>            lentIncentivesPerTokenPerEpoch[principle][
                    hashVariables(incentivizeToken, epoch)
                ] += amount;
            } else {
@>            borrowedIncentivesPerTokenPerEpoch[principle][
                    hashVariables(incentivizeToken, epoch)
                ] += amount;
            }

            ...
        }
    }

Root Cause

In DebitaIncentives::incentivizePair, the return value of ERC20.transferFrom is not checked. Additionally, the bribe token is not validated against the whitelist, allowing an attacker to use a token that does not revert on a failed transfer, but instead returns false.

Internal pre-conditions

No response

External pre-conditions

No response

Attack Path

  1. The attacker calls the incentivizePair function, passing an incentiveToken parameter (an array with a single element) that points to a token which does not revert on failed transfers.
  2. The attacker deliberately fails to provide the necessary token allowance to the DebitaIncentives contract, causing the transferFrom function to fail and return false instead of reverting.
  3. As a result, the contract incorrectly updates its state, despite no actual transfer of tokens taking place.

Impact

  • The contract's balance may be artificially inflated, as no tokens are actually transferred to the protocol.

PoC

No response

Mitigation

Implement a whitelist for bribe tokens and use safeTransferFrom instead of transferFrom to ensure proper token transfer handling and security.