Started at March-23–2022 16:20:08 UTC+8, CashioApp was exploited to drain the collateral token account at the loss about 52 millions. The hack was made possible due to the insufficient check of input accounts that allows the attacker to mint 20 billion $CASH
tokens without any deposit. In the following, we show the technical details.
Summary
The incident was due to a bug in the Brrr program that is designed to handle the minting and burning of $CASH
tokens with the collateral of Saber LP Arrows. Specifically, users can print $CASH
, which means minting $CASH, by depositing Arrow
LP tokens. Note that Arrow LP token receive the Saber LP token as the underlying tokens. The print_cash
instruction, which can mint $CASH
, receives a list of accounts including the Bank
account and the Collateral
account. They are used to record and track the collateral (i.e., Arrow
LP tokens) that is allowed to be used for minting $CASH
. By design, these two accounts should only be initialized and authorized by the admin. However, the program fails to check the validity of the Bank
account. As a result, the attacker can craft a series of fake accounts (including the Bank
account) to feed into the instruction print_cash
, and print $CASH
for almost free (the only cost is transaction fees).
Details
Let’s start the analysis from the used accounts of instruction print_cash
below.
The attribute common
(line 75) is a struct whose type is BrrrCommon
in the program. In BrrrCommon
, the bank
account and the collateral
account are initialized and authorized by the admin. The crate_token
is the account of the $CASH
token, which stores information about $CASH
, such as the public key of the crate_mint
(line 107), the public keys of admin roles, and more. The crate_collateral_tokens
is a vault account that holds the collateral tokens transferred from users. Since the collateral should be Arrow
LP tokens, which receive the LP tokens of Saber
, users have to input the related accounts of saber_swap
. The last two attributes in struct BrrrCommon
are program IDs of target programs used in the instruction. Note that the last four attributes in struct PrintCash
are the user's system account (also the signer of the transaction), the user's collateral account, the user's $CASH
token account that receives the minted $CASH
, and the pubkey of the account that has the authority to mint the $CASH
.
The Attack Transaction
After understanding the functionality of above accounts, we then start to analyze the attack transaction: 0x4fgL…z2K5. This attack is initialzied from the attacker address (located at 0x6D7f) and the list of input accounts in the instruction PrintCash
is shown below.
The Account #1
(0x5aha) above corresponds to the Bank
account. We noticed that it's different from the address provided on the CashioApp's
official website (0xEm1P), which means the validation of Bank
account is insufficient!
Validation
Let’s take a closer look at the validation of the struct BrrrCommon
in the code to figure out how the bypass works.
The only check of the input Bank
account is to ensure the input Collateral account is associated with the Bank
account (line 12). However, it can be easily bypassed by providing a fake Collateral
account as well. Besides, to avoid paying real collateral assets, the attacker also provided fake saber_swap
accounts. Note that the attacker aims to deposit unvaluable collateral assets to print valuable $CASH
tokens, so the crate_token
and the crate_mint
provided by the attacker should be true addresses. In other words, the insufficient check of the Bank
account enables the attacker to craft a series of fake accounts to print $CASH
with unvaluable collateral.
The Fix
The fix is to add the statement of assert_keys_eq!(self.bank.crate_mint, self.crate_mint)
. This statement ensures the Bank
account's crate_mint
is the correct crate_mint
for $CASH
. However, how does it ensure the Bank
account is valid? Let's take a look at the NewBank
struct (in program bankman
) and the NewCrate
struct (in program crate_token
) to find the answer.
In fact, the Bank
account is a PDA
whose seeds contain the address of the crate_token
. Meanwhile, the crate_token
is also a PDA
whose seeds contain the address of the crate_mint
. That ensures that the Bank
account is valid if the input crate_mint
is valid. Without a correct crate_mint
, attackers cannot mint the $CASH
and cannot launch the attacks.
About BlockSec
BlockSec is a pioneering blockchain security company established in 2021 by a group of globally distinguished security experts. The company is committed to enhancing security and usability for the emerging Web3 world in order to facilitate its mass adoption. To this end, BlockSec provides smart contract and EVM chain security auditing services, the Phalcon platform for security development and blocking threats proactively, the MetaSleuth platform for fund tracking and investigation, and MetaSuites extension for web3 builders surfing efficiently in the crypto world.
To date, the company has served over 300 esteemed clients such as MetaMask, Uniswap Foundation, Compound, Forta, and PancakeSwap, and received tens of millions of US dollars in two rounds of financing from preeminent investors, including Matrix Partners, Vitalbridge Capital, and Fenbushi Capital.
Official website: https://blocksec.com/
Official Twitter account: https://twitter.com/BlockSecTeam