πŸ“„

Report #12997

Report Date
October 30, 2022
Status
Closed
Payout

Reentrancy with ERC677/777 tokens gives rise to unlimited balance (no funds at risk - yet)

β€£
Report Info

Report ID

#12997

Target

Report type

Smart Contract

Impacts

Direct theft of any user funds, whether at-rest or in-motion, other than unclaimed yield

Has PoC?

Yes

Bug Description

Account balance calculation in TokenFacet is vulnerable to reentrancy, which leads to potentially unlimited balance for ERC777 tokens - some of which are listed in CurveRegistry w/ $10M-$20M pool balances.

Impact

Currently none, this will change if Beanstalk adds any ERC777 tokens to its Deposit Whitelist i.e. pBTC, imBTC, AMP etc.

Risk Breakdown

Difficulty to Exploit: Medium Weakness: Reentrancy allows attacker to inflate their account internal balance, and potentially drain the core Beanstalk Protocol pool if any ERC777 tokens become eligible on the whitelist. CVSS2 Score:

Recommendation

And reentrancy guard on TokenFacet OR on the vulnerable functions - transferToken and receiveToken in the LibTransfer library. The latter is recommended, as LibTransfer is used across multiple Beanstalk Facet contracts.

References

Whitehat has previously discovered similar inflated balance bugs in Wormhole, Thorstarter etc.

Proof of concept

Let me know if you need the following coded. Here's the pseudo:

  1. Call function transferToken from TokenFacet per delegatecall in Beanstalk with an ERC777 token
  2. transferToken balance calculation in LibTransfer does the following:
  • Measure initial contract balance
  • Call safetransferfrom on token contract -> Attacker re-enters here using _calltokenstosend function of ERC777 tokens
  • Measure final contract balance
  1. Balance credited is equal to final balance - initial contract balance
  2. During reentry, the attacker calls transferToken again, thereby securing a low initial contract balance
  3. Balance credited is then erroneously calculated due to incorrect initial balance

Taking an example of 100 units of an arbitrary ERC777 token (initially with 0 balance), only looped twice

  1. On first loop, initial balance = 0
  2. Attacker re-enters during Safetransferfrom loop to call transferTokens again with 100 units
  3. On second loop, initial balance = 0
  4. Attacker chooses to not re-enter during safetransferfrom and 100 units are transferred
  5. Final balance calculation for second loop: balanceOf(beanstalk) = 100
  6. Final balance for first loop = 200
  7. For the second loop, attacker is credited (correctly): 100 - 0 = 100
  8. For the first loop, attacker is erroneously credited: 200 - 0 (wrong!) = 200

Hence, for a 200 unit token transfer, attacker is credited 100 + 200 = 300.

This effect magnifies with each successive loop due to initialBalance being erroneously measured as '0' due to re-entry.

With this erroneously high balance, attacker can then carry out an attack on Beanstalk i.e. trade this token and its BDV for other assets, or withdraw this balance if there is a sizeable chunk of ERC777 tokens already in pool.

Again, this is currently NOT profitable as there are no ERC777 tokens on the deposit whitelist, so this report is more a warning if this were to change in future.

BIC Response

This submission is out of scope because it is related to code / functionality that is not deployed. The submission explicitly states that the impact is none as the Deposit Whitelist does not currently support ERC 777 tokens. Thus, there is no risk either.

Because of these reasons, this submission not eligible for a reward.

Halborn Response

If you are not supporting ERC777 tokens right now, then it’s not a risk.