Platform: Code4rena
Start Date: 09/12/2022
Pot Size: $90,500 USDC
Total HM: 35
Participants: 84
Period: 7 days
Judge: GalloDaSballo
Total Solo HM: 12
Id: 192
League: ETH
Rank: 28/84
Findings: 3
Award: $456.10
🌟 Selected for report: 1
🚀 Solo Findings: 0
🌟 Selected for report: HollaDieWaldfee
Also found by: 0xbepresent, 0xsomeone, Ruhum, ali_shehab, cccz, csanuragjain, kaliberpoziomka8552, rvierdiiev, sha256yan
81.4983 USDC - $81.50
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Lock.sol#L78-L92
The Lock
contract is meant to be the manager
of the BondNFT
implementation and performs accounting of asset inflow and outflow via the totalLocked
variable that is incremented during a lock
and decremented during a release
. The issue arises in the fact that the extendLock
function can increase the assets of a particular bond but does not increment the totalLocked
variable.
As a result, when the release
function is executed the totalLocked
variable will be decremented for more than it has accounted for thus causing whatever funds were deposited using extendLock
to be un-retrievable either for the user that deposited them or, in a worst case malicious attack, for the remaining users that have yet not withdrawn their locks.
We can create a 7-day empty bond and then invoke extendLock
with a significant amount of funds, specifying the minimum period possible.
If no one detects our significantly large deposit for 7 days and withdraws, we can perform a withdrawal at the end and all funds we have deposited will "tap" into the totalLocked
allocation of other deposits. This will cause the other deposits to no longer be withdrawable due to an underflow that would occur in release
.
Given that you cannot release
a bond early, the attack is trivial to execute if users specify a period larger than 7
days for their deposit (which they are presumably incentivized to do so under the Tigris ecosystem).
Manual review.
We advise the totalLocked
variable to be properly incremented during an extendLock
operation as well. Given that the variable entry is purely utilized for off-chain purposes, it could potentially be omitted entirely as well since other measurement methodologies can be used such as actual EIP-20 asset balances.
#0 - c4-judge
2022-12-22T15:15:05Z
GalloDaSballo marked the issue as duplicate of #23
#1 - GalloDaSballo
2022-12-22T15:15:30Z
No code snippets, No Poc, will award 50%
#2 - c4-judge
2022-12-22T15:15:33Z
GalloDaSballo marked the issue as partial-50
🌟 Selected for report: unforgiven
Also found by: 0xsomeone, KingNFT, debo, hihen, mookimgo, rotcivegaf, stealthyz, wait
201.2303 USDC - $201.23
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Position.sol#L148
The Position
contract performs a _safeMint
operation when actually creating a position via mint
. The vulnerability arises from the code's deviation from the Checks-Effects-Interactions (CEI) pattern and in particular, the initId
entry written to after creation internally as well as the limitDelay
entry written to after creation in the initiateLimitOrder
function of Trading
. This re-entrancy can be exploited in two ways and as such, this exhibit can be considered as counting for either one or two major vulnerabilities (in the past, some C4 contests have permitted the same flaw exploited in a different manner to be counted twice).
The first vulnerability is significant as it causes the trades
function to yield a significantly inflated accInterest
variable. This can be exploited by creating a position via initiateMarketOrder
in the Trading
contract and invoking addToPosition
right afterwards. All validation checks are passed and the position now permanently stores the invalid accInterest
to storage
via the setAccInterest
function.
The second vulnerability is also significant and arises from the inexistent prevention of a limit-order duration. Given that limitDelay
is never written to, it is possible to immediately create a limit order and consume it in the same transaction via executeLimitOrder
further compromising the system by being able to acquire an instant profit.
For the first vulnerability, we can observe that the initId
entry is written to with a default value causing calculations in the trades
function to yield a zero-value in accInterest
for a properly initialized NFT. Given that we can re-enter all contracts of the system, we can invoke the addToPosition
function with a zero amount to permanently store the inflated accInterest
value that is temporarily possible in the hijacked mint
call.
All logical checks (_checkOwner
, _checkDelay
, tradingExtension.validateTrade
, _checkVault
) will be passed successfully as the entries the mint
function of Position
writes to after _safeMint
are solely utilized during the burn operation and even then remain unvalidated. At this point, we have managed to permanently store the inflated accInterest
value which we can claim after the block delay for positions has passed.
For the second vulnerability, we can observe that the limit order delay is written to after the mint
operation concludes. This permits us to exploit it, closing our limit order immediately to acquire a profit as well as completely corrupt the storage of Position
as it would delete the index of our yet-uncreated position (which is by default 0
) in the executeLimitOrder
function.
Manual review of the codebase.
We advise a _mint
operation to be utilized instead of a _safeMint
operation as a callback operation on the receiver of the NFT is in-fact redundant for the use case of the Tigris protocol. This will completely alleviate both vulnerabilities as they would no longer be possible.
#0 - c4-judge
2022-12-21T15:05:21Z
GalloDaSballo marked the issue as duplicate of #400
#1 - c4-judge
2023-01-22T17:41:12Z
GalloDaSballo marked the issue as satisfactory
🌟 Selected for report: 0xsomeone
Also found by: 0xhacksmithh, 8olidity, Critical, Ruhum, SamGMK, Secureverse, Tointer, __141345__, aviggiano, rotcivegaf
173.3691 USDC - $173.37
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/StableVault.sol#L39-L51 https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/StableVault.sol#L60-L72
The StableVault
contract attempts to group all types of stablecoins under a single token which can be minted for any of the stablecoins supported by the system as well as burned for any of them.
This is at minimum a medium-severity vulnerability as the balance sheet of the StableVault
will consist of multiple assets which do not have a one-to-one exchange ratio between them as can be observed by trading pools such as Curve as well as the Chainlink oracle reported prices themselves.
Given that the contract exposes a 0% slippage 1-to-1 exchange between assets that in reality have varying prices, the balance sheet of the contract can be arbitraged (especially by flash-loans) to swap an undesirable asset (i.e. USDC which at the time of submission was valued at 0.99994853
USD) for a more desirable asset (i.e. USDT which at the time of submission was valued at 1.00000000
USD) acquiring an arbitrage in the price by selling the traded asset.
To illustrate the issue, simply view the exchange output you would get for swapping your USDC to USDT in a stablecoin pool (i.e. CurveFi) and then proceed to invoke deposit
with your USDC asset and retrieve your incorrectly calculated USDT
equivalent via withdraw
.
The arbitrage can be observed by assessing the difference in the trade outputs and can be capitalized by selling our newly acquired USDT
for USDC
on the stablecoin pair we assessed earlier, ultimately ending up with a greater amount of USDC
than we started with. This type of attack can be extrapolated by utilizing a flash-loan rather than our personal funds.
Manual review of the codebase, Chainlink oracle resources, Curve Finance pools.
We advise the StableVault
to utilize Chainlink oracles for evaluating the inflow of assets instead, ensuring that all inflows and outflows of stablecoins are fairly evaluated based on their "neutral" USD price rather than their subjective on-chain price or equality assumption.
#0 - GalloDaSballo
2022-12-20T16:11:48Z
The warden has shown how, due to an incorrect assumption, the system offers infinite leverage.
This can be trivially exploited by arbitraging with any already available exchange.
Depositors will incur a loss equal to the size of the arbitrage as the contract is always taking the losing side.
I believe this should be High because of it's consistently losing nature
#1 - c4-judge
2022-12-20T16:11:54Z
GalloDaSballo changed the severity to 3 (High Risk)
#2 - c4-judge
2022-12-20T16:11:59Z
GalloDaSballo marked the issue as primary issue
#3 - TriHaz
2023-01-10T14:35:10Z
We are aware of this issue, we will keep the vault with one token for now.
#4 - c4-sponsor
2023-01-10T14:35:18Z
TriHaz marked the issue as sponsor acknowledged
#5 - c4-judge
2023-01-22T17:36:30Z
GalloDaSballo marked the issue as selected for report