Beanstalk Insufficient Input Validation Bugfix Review
Beanstalk Introduction
Beanstalk is a credit-based stablecoin protocol on Ethereum that aims to reinvent the existing collateralized stablecoin market. Unlike traditional models relying on collateral, Beanstalk uses a credit system to create a decentralized and liquid asset.
The protocol introduces BEAN, its stablecoin, as the core of an Ethereum-native, rent-free economy. Beanstalk primarily focuses on encouraging participants to balance the BEAN price around $1 by adjusting the supply based on its creditworthiness.
When BEAN prices are below $1, the protocol attracts lenders to stabilize the value, and when prices go too high, new BEANs are minted and distributed. This inflationary mechanism forms the foundation of the Beanstalk economy. You can read more about Beanstalk and its architecture here.
Vulnerability Analysis
Among the major five components of Beanstalk, the Silo functions as the Beanstalk DAO. It allows depositors to deposit their BEANs and other whitelisted LP tokens in exchange for passive yield opportunities.
The conversion between Bean and LP Deposits within the Silo is vital for maintaining the peg and is carried out through the convertFacet
. This convert feature is like a tool that lets users swap their BEANs for LP tokens when prices are high and LP tokens for BEANs when prices are low, as long as the type of conversion is whitelisted. This helps balance things out and maintain a stable price.
Let’s examine this convert function and its logic and understand the source of the vulnerability
This function invokes two internal functions. Let’s examine each one separately.
1. Consider `convertData.convertWithAddress()`
Here, the input data provided by the user (convertData) is decoded to get token amounts and an address, which is essentially the wellLp address.
The issue is that there’s no validation on this Well address, allowing anyone to provide a malicious contract as the Well address.
2. _wellRemoveLiquidityTowardsPeg
In the _wellRemoveLiquidityTowardsPeg()
function, the decoded Well address is used to obtain the BEANs amount (amountOut
).
A Well address (malicious contract) can return the entire BEAN balance of the Beanstalk contract as the amountOut
.
Furthermore, the lpToPeg()
function also makes calls to the same Well address, and based on that returned data, lpConverted
amount is determined. This puts lpConverted
amount essentially under the control of the attacker, allowing them to set it to zero. Consequently, amountIn
becomes zero.
Now, when the process returns to _withdrawTokens
within the convertFacet.convert
function, it can be entirely bypassed by submitting empty stems
and amounts
arrays.
So, in essence:
toToken
= BEANfromToken
= Malicious WelltoAmount
= It can be anything as it’s returned by a malicious Well. (e.g., bean.balanceOf(beanstalk))fromAmount
= 0
Ultimately, due to the aforementioned insufficient input validation, this function allowed the deposit of beans without withdrawing any tokens from the Silo, which can later be easily withdrawn.
Proof of Concept (PoC)
The Immunefi team prepared the following PoC to demonstrate the explained vulnerability.
Output
Vulnerability Fix
To mitigate the vulnerability, Beanstalk committed the following checks to ensure that the provided address is indeed a valid Well address.
They also added a check for the fromAmount
, ensuring that it’s always greater than zero at this commit
Acknowledgments
We would like to thank the whitehat nicole for doing an amazing job and making a responsible disclosure to Beanstalk. Big props also to the Beanstalk Immunefi Committee, who did an amazing job responding quickly to the report and resolving it.
If you’re a web2 or web3 developer who is thinking about a bug-hunting career in web3, we got you. Check out the Web3 Security Library, and start earning rewards on Immunefi — the leading bug bounty platform for web3 with the world’s biggest payouts.
And if you’re feeling good about your skillset and want to see if you will find bugs in the code, check out the bug bounty program from Beanstalk.