Final Review: Fuji Finance Audit Competition and Winners Announcement!
Web3 audits are evolving. In the past, projects needed to wait months or break the bank to find a good auditor. As a security project, we can relate to this. Because of this, we made the decision to upgrade our security offering to a more complete and advanced set of products.
Decentralized audit competitions are a great way for web3 security researchers to participate in the protection of crypto projects. Audit challenges usually last a few weeks and they are a powerful way to get as many auditors as possible to review a codebase before an important launch.
At Hats, we encourage projects to perform audits with trusted firms and to use audit competitions as an additional security measure. With our native product, projects only pay if valid vulnerabilities are discovered. Therefore, it makes sense to conduct an audit competition just before launching a new product or feature.
The deployment of competitions is free, and projects only pay a service fee if there are actual findings. Creating an on-chain competition only takes a few steps, and projects can easily access a network of over 150 security researchers!
At Hats vulnerabilities are disclosed on-chain and in the respective GitHub repo simultaneously. This means auditors can check submitted entries and decide if they want to continue searching for more bugs. This system allows us to reward the best auditors in the industry, embrace transparency, and foster a competitive environment.
With the on-chain vulnerability disclosure method, projects can be assured that potential issues are addressed and solved prior to going live. If no issues are found, funds can be easily withdrawn, allowing the project to move forward with even greater confidence
About the competition
On Feb 14th we launched an audit competition for Fuji Finance and in total we received 45 submissions. The Fuji Finance committee was impressed by the quality and amount of findings, and is very thankful for the hard work and dedication of every participant. If you were one of the winners, expect payment by March 31, 2023!
Below is a summary of eligible vulnerability disclosures:
3 High-severity disclosures :
0x9…1AE
0x9…1AE
0xC…Cc2
Github Issue 311: Incorrect gainedShared calculation when call function. The report identifies that the liquidation function doesn’t handle decimals of collateral and debt properly. This may hinder the ability to liquidate positions in vaults in which collateral has decimals not equal to 18.
Github Issue 323: An attacker can deposit on behalf of users. The vulnerability arises from giving more than the required erc20-allowance to the router. This applies both for a deposit or payback action. Essentially allowing to move funds on behalf of the user. There can be a situation in which for no reason someone triggers a deposit or payback function that pulls funds from the user, even if not desired. Vaults need to be validated.
Github Issue 333: The FujiOracle will return the wrong price for an asset if the underlying aggregator hits minAnswer. This vulnerability is known and in fact is how lending platforms got bad debt when the UST price crashed. There is a need to create alternate ways to confirm the price.
6 Medium-severity disclosures:
0x9…1AE
0x1…a27
0x9…1AE
0x1…a27
0x9…1AE
0x6…f97
Github Issue 293: An attacker can withdraw assets without burning any shares. The vulnerability root claim is that totalShares and totalAssets can be such that attempting to withdraw 1–10 wad assets results in zero burns of shares.
Github Issue 307: TimeLock can prevent ERC-4626 compliance due to setting a Lowered deposit cap. BaseVault.sol has a function that allows the timelock to input a deposit cap, setDepositCap(uint256). The function allows setting the cap as zero or below the minimum vault amount. However, it does not prevent the timelock from setting an amount lower than currently stored in the vault. This will make maxDeposit() call to revert.
Github Issue 315: Inflation attack with BorrowingVault.sol when the provider is Aave2. Since AaveV2 provider utilizes erc20-balanceOf to determine the amount of assets owned by the vault, it is exposed to an inflation attack as described. Proper measures must be set to avoid inflation attacks.
Github Issue 320: Timelock can increase max LTV to >100%, enabling undercollateralized loans. The borrowing vault has functions that modify its risk parameters. One of these functions being setMaxLtv(), which has a lower bound of 1%. However, setMaxLtv() does not have any upper bound, meaning the timelock has the ability to increase the loan-to-value amount to above 100%. In the scenario where this happens, loans could be undercollateralized, making it profitable to borrow as many times as possible and leave the protocol with bad debt. Any value above 100% will cause this vulnerability.
Github Issue 330: Missing transfer fees from contract flasherBalancer. Balancer flasher contract is missing approval to transfer asset fee. This is not a problem for when fee == 0, however, Balancer has the ability to modify the fee rate. If that were to happen BalanceFlasher becomes inoperable.
Github Issue 341: An attacker can withdraw the contract’s token balance. In the context of contracts in tag v.0.0.1, the funds that can remain in the BaseRouter.sol contract are if:
1) the user sends directly the funds
2) the funds are stuck from a previously failed xReceive call.
Unaccounted funds lingering in the ConnextRouter can be extracted using xReceive.
4 valid gas submissions but only 2 winners
0xB…4Ad 1st place
0x8…246 2nd place
As described in the initial competition rules, only two winners were to be selected for the highest level of gas optimization achieved. Optimizations in BaseRouter and BaseVault were prioritized over anything.
In general both 1st and 2nd place proposed that the counter in for-loops should not be initialized with zero and to remove unused parameters in multiple contracts.
The first place submission was more thorough in reviewing the optimizations including the greatest optimization which included moving the beneficiary check from the state variable to memory in the _bundleInternal().
Other general recommendations done by the 1st place winner were making constructors and setter functions payable, breaking loops when checking if an element is inside an array, and caching data into local memory in certain functions instead of reading multiple times from state.
21 Low (not qualified for bounty)
Various submissions were classified as low risk, and here are some reasons why:
- Submissions assumed that the BaseVault minAmount was set to 1 wad. However, the code was explicit in setting minAmount to 1e6. Although this value could be changed by the TimeLock, it is not the intention as the team is aware of the regular ERC4626 inflation attacks. This was noted in the code and many submissions took this angle of attack.
- Submission assumed use of non-standard ERC-20 implementations.
- Submission overlooked that the contract system has workarounds to avoid specific DOS.
- Submission addressed specific edge cases such as: interacting with blacklisted addresses (resulting only in DOS for those addresses), oracles returning negative values, or interacting with vaults with malign ERC-20 implementations.
11 Disqualified submissions
Various submissions were disqualified due to the following reasons:
- A similar submission was previously done.
- The on-chain submission provided no links to the GitHub issue.
- The submission made assumptions out of scope or ignored existing checks in the contracts.
- The submission was incomplete and with poor information.
Final Remarks from Fuji committee:
Overall, the Fuji team is happy with all the submissions. The process of setting up the competition can be improved and perhaps require less manual input from the project setting up the competition -Work in progress!
Competition rules need to be standardized to avoid variable components across competitions, this will help security researchers get familiar with the format — Work in progress!
Overall, the Fuji team believes that the process of having a competition is complementary to a regular security audit and it is not a replacement for the effort of a traditional audit.- The Hats team believes audit competitions serve as an extra layer of security on top of audits, especially before deployment. We work with teams to ensure they have been audited in the past, and are seeking extra security from our products.
Fuji Finance also provided insightful feedback regarding the Hats scoring system, which we will take into consideration while aligning with web3 standards of decentralization, trust, and transparency.
Moving forward, we will allow projects to openly share their feedback regarding Hats’ competitions and bug bounties in our articles. This is with the intention of being transparent along the way and allowing community members to witness our growth.
Congratulations to all the winners! We thank all participants for their hard work and the Fuji Finance team for trusting Hats with their security needs. Stay on the lookout for a new audit competition coming to Hats Finance soon!
Until then — stay safe!