Closed sherlock-admin closed 1 year ago
2 comment(s) were left on this issue during the judging contest.
141345 commented:
l
0xyPhilic commented:
invalid because you can't provide a random market - only added markets by the owner can be used
This is a valid callpath but since the MultiInvoker should never hold DSU we would consider this low/informational.
Since MultiInvoker does not hold fund, there should not be fund loss if the protocol runs as expected. This contract could only have fund by accidenty. Based on Sherlock's criteria, this should be of low severity.
0xTheC0der
high
DSU token balance of MultiInvoker contract can be drained by anyone
Summary
Due to a missing
marketFactory.instances(market)
check when performing aPerennialAction.UPDATE_POSITION
via MultiInvoker.invoke(...), anyone can drain the wholeDSU
token balance by providing a fakeMarket
contract.Vulnerability Detail
Although, the
MultiInvoker
contract is - as its name says - an invoker contract, it can hold a non-zero balance ofDSU
tokens due to its market & vault update mechanism, which is mostly handled correctly see L204 and L301. Moreover, such a non-zero balance state requires a validity check of markets/vaults before giving token allowance to them, see MultiInvoker._approve(...).However, when calling MultiInvoker ._update(...)
by performing a
PerennialAction.UPDATE_POSITION
via MultiInvoker.invoke(...), the providedIMarket market
contract is not validated usingmarketFactory.instances(market)
, therefore one can create a fakeMarket
contract that does nothing onmarket.update(...)
.Impact
As a cosequence, an attacker can invoke a
PerennialAction.UPDATE_POSITION
using a fakeMarket
contract in order to withdraw an arbitrarycollateral
amount ofDSU
tokens, see MultiInvoker._withdraw(...), which leads to loss of funds for the protocol. Furthermore, one can specify to unwrap theDSU
tokens and therefore withdrawUSDC
instead.Note that this vulnerability also exists on
PerennialAction.LIQUIDATE
, see MultiInvoker._liquidate(...), but the attack path is easier using the discussed way.Code Snippet
The following PoC modifies the existing test case "withdraws collateral" to demonstrate the above attack path by having an unrelated attacker account with a fake
Market
contract withdrawDSU
tokens from theMultiInvoker
contract.Just apply the diff below and run the test case in
perennial-extensions
withnpx hardhat test test/unit/MultiInvoker/MultiInvoker.test.ts
:Tool used
Manual Review
Recommendation
Always require
Market
andVault
instances to be valid (via their respective factories). A working example is already given by MultiInvoker._approve(...).