FEI and TRIBE Redemption contest - cccz's results

A new DeFi primitive that allows any token to become productive and provide FEI liquidity at no cost to the markets that need it most.

General Information

Platform: Code4rena

Start Date: 09/09/2022

Pot Size: $42,000 USDC

Total HM: 2

Participants: 101

Period: 3 days

Judge: hickuphh3

Total Solo HM: 2

Id: 161

League: ETH

Tribe

Findings Distribution

Researcher Performance

Rank: 2/101

Findings: 2

Award: $18,933.67

🌟 Selected for report: 1

🚀 Solo Findings: 1

Findings Information

🌟 Selected for report: cccz

Labels

bug
2 (Med Risk)
sponsor disputed

Awards

18900 USDC - $18,900.00

External Links

Lines of code

https://github.com/code-423n4/2022-09-tribe/blob/769b0586b4975270b669d7d1581aa5672d6999d5/contracts/shutdown/redeem/TribeRedeemer.sol#L44-L61

Vulnerability details

Impact

In the TribeRedeemer contract, the user provides redeemedToken to redeem the tokens in the list. The transaction will revert when the balance of tokens in the list is 0. This prevents the user from losing their redeemedToken if they redeem when there are no tokens in the contract.

for (uint256 i = 0; i < tokensReceived.length; i++) { uint256 balance = IERC20(tokensReceived[i]).balanceOf(address(this)); require(balance != 0, "ZERO_BALANCE"); // @dev, this assumes all of `tokensReceived` and `redeemedToken` // have the same number of decimals uint256 redeemedAmount = (amountIn * balance) / base; // 10^6 * 10^18 / 10^8*10^6 amountsOut[i] = redeemedAmount; }

However, a malicious user could send tokens in the list to the TribeRedeemer contract so that the token balance is not 0. This would allow the redeem function to work, and the user would suffer a loss when they redeem early by mistake.

Proof of Concept

https://github.com/code-423n4/2022-09-tribe/blob/769b0586b4975270b669d7d1581aa5672d6999d5/contracts/shutdown/redeem/TribeRedeemer.sol#L44-L61

Tools Used

None

Consider making the TribeRedeemer contract inherit the Pausable contract and allow users to redeem when a sufficient number of tokens have been sent to the contract

#0 - thomas-waite

2022-09-19T13:44:16Z

Do not understand what the issue presented is. If the attacker sends funds to the contract so the balances are not 0, then the user would be able to redeem as normal. How do they suffer any loss if they 'redeem early'?

The balances will only be 0 when all users have redeemed. Not an issue

#1 - thereksfour

2022-09-20T13:11:08Z

@thomas-waite Consider the following scenario.

  1. there are no reward tokens in the TribeRedeemer contract now, (the administrator will transfer 100M reward tokens to the contract in exchange for the user's redeemedToken only after some time).
  2. when the user provides redeemedToken to call the redeem function, the transaction reverts in the previewRedeem function because the reward token balance is 0 (this prevents the user from getting 0 reward tokens).
for (uint256 i = 0; i < tokensReceived.length; i++) { uint256 balance = IERC20(tokensReceived[i]).balanceOf(address(this)); require(balance != 0, "ZERO_BALANCE");
  1. a malicious user can send 100 reward tokens to the contract in advance.
  2. At this point, if the user calls the redeem function, the transaction will not revert and the contract will exchange the 100 reward tokens for the user's redeemedToken. The user could have exchanged the redeemedToken for more reward tokens, but the user only got a small amount of reward tokens

#2 - HickupHH3

2022-09-28T06:55:09Z

Redemptions can only begin when the contract has non-zero balances for all redeemed tokens, but the start redemption time isn't explicitly stated.

Malicious users can break this assumption by sending paltry amounts to the contract as explained above. Naiive users might begin redemptions early, thus losing out on the tokens they would've otherwise received after the full redemption token amounts have been sent to the contract.

It is unclear if there is a time lag between the contract deployment and time at which redemption funds are sent, and if so, its duration.

While unlikely to happen, it would be a case of users losing out on rewards they should be entitled to. Hence, I'm siding with the warden in this instance.

#3 - thomas-waite

2022-10-18T13:24:42Z

@HickupHH3 , the contract gets deployed ahead of time by necessity (the address is needed for the DAO vote). The DAO vote which funds the contract executes after deployment, there is a time lag of >= 3 days.

I do not agree that the situation described is a vulnerability in the contract and instead it would be down to user/deployer error. Clearly, no user was encouraged to redeem before funds were available and the contract address was not publicised. So no user attempted to redeem before funds were available.

#4 - HickupHH3

2022-10-18T14:15:54Z

I respectfully disagree.

There is no doubt that there a number of prerequisites to enable this attack, which makes the likelihood low:

  • Malicious actor has to know what the redeemer contract is
  • Malicious actor has to deposit some tokens into redeemer contract
  • Malicious actor must be able to trick users into redeeming early

From a game theory POV, small TRIBE holders could band together to target a few large TRIBE holders.

With these external requirements, it is only then that we will see what could be deemed as "protocol leaked value".

2 — Med: Assets not at direct risk, but the function of the protocol or its availability could be impacted, or leak value with a hypothetical attack path with stated assumptions, but external requirements

The scenario thankfully remained hypothetical.

[Low-01] Hardcoded token address

Hardcoded DAI and FEI token addresses are used in SimpleFeiDaiPSM contract, this is not a good practice, if the token address changes make the contract unusable, variables should be used as the token address

https://github.com/code-423n4/2022-09-tribe/blob/769b0586b4975270b669d7d1581aa5672d6999d5/contracts/peg/SimpleFeiDaiPSM.sol#L15-L20

[Low-02] RariMerkleRedeemer: signAndClaim should use hasNotSigned modifier

In the RariMerkleRedeemer contract, the hasNotSigned modifier should be used when the function requires the user to provide a signature, like the sign and signAndClaimAndRedeem functions, so signAndClaim should also use the hasNotSigned modifier.

https://github.com/code-423n4/2022-09-tribe/blob/769b0586b4975270b669d7d1581aa5672d6999d5/contracts/shutdown/fuse/RariMerkleRedeemer.sol#L88-L97

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