Closed code423n4 closed 1 year ago
I think this is a duplicate of the warden's other finding #578 which he refers to. What distinguishes these is only the conclusion of what the issue actually is. In #578 it is claimed that being able to borrow without DBR is the issue. Here it is claimed that the proposed mitigation of #578 can by bypassed essentially by "pretending" to have DBR when one really does not (i.e. by borrowing DBR). What these two issues have in common, however, is the withdrawal just before the front-running. The front-running itself is completely irrelevant, but the withdrawal obviously causes some problem. The real issue is that the attacker can end up with zero debt and zero collateral, but still have a DBR deficit.
The core problem seems to be that the collateral only covers the DOLA debt, but not the DBR deficit. Forced replenishment is meant to correct DBR deficit by forcing the borrower to loan more DOLA which is used to pay for his deficit. Liquidation is meant to correct having too much debt by turning collateral into DOLA to repay some of the debt. This means that forced replenishment is, as a deterrent, dependent on the possibility of consequential liquidation. For liquidation to be possible there must be some collateral left. It is currently not possible to withdraw collateral such that the DOLA debt isn't covered by it. But there is no check on the impact on DBR deficit (which also is a kind of debt). This is precisely what is missing; the user should not be able to withdraw more than that both his DOLA debt and his DBR deficit can be covered by his collateral through forced replenishment and liquidation. This is reported by (at least?) #311 and #366.
For a related discussion on different debt levels and their impact on liquidation, see my comment on #395.
08xmt marked the issue as sponsor disputed
After reviewing @08xmt comments I am going to mark this as a duplicate of #401 which I do believe is the underlying issue.
the user should not be able to withdraw more than that both his DOLA debt and his DBR deficit can be covered by his collateral through forced replenishment and liquidation.
0xean marked the issue as duplicate of #401
Issue marked as satisfactory as requested by 0xean
Simon-Busch marked the issue as duplicate of #583
Lines of code
https://github.com/code-423n4/2022-10-inverse/blob/main/src/DBR.sol#L170-L178 https://github.com/code-423n4/2022-10-inverse/blob/main/src/DBR.sol#L188-L202 https://github.com/code-423n4/2022-10-inverse/blob/main/src/Market.sol#L408-L410 https://github.com/code-423n4/2022-10-inverse/blob/main/src/Market.sol#L389-L401 https://github.com/code-423n4/2022-10-inverse/blob/main/src/Market.sol#L559-L572 https://github.com/code-423n4/2022-10-inverse/blob/main/src/Market.sol#L531-L539 https://github.com/code-423n4/2022-10-inverse/blob/main/src/Market.sol#L472-L474 https://github.com/code-423n4/2022-10-inverse/blob/main/src/Market.sol#L460-L466
Vulnerability details
Impact
Although my other finding named "DOLA can be borrowed without owning any DBR" indicates that users who do not own any DBR can still borrow DOLA, the design still appears to only allow the DBR owners to borrow DOLA; this is confirmed by https://github.com/code-423n4/2022-10-inverse#fixed-rates-market-protocol-overview, which states that "one DBR token gives the right to borrow one DOLA for one year", and https://github.com/code-423n4/2022-10-inverse#contracts, which states that "a DOLA Fed mints DOLA to a market, which is then available to borrow for users holding DBR, using the Borrow function".
However, assuming that owning DBR is required before DOLA can be borrowed, the
DolaBorrowingRights
contract'stransfer
andtransferFrom
functions can be utilized to share DBR between users for bypassing such requirement. For example, Alice and Bob both use contracts to interact with theMarket
contract. Alice's contract owns some DBR while Bob's does not. Alice's contract can send one transaction that deposits her collateral and borrows DOLA first and then transfers DBR to Bob's contract; after owning some DBR at this moment, Bob's contract can send one transaction that deposits his collateral and borrows DOLA first and then transfers the received DBR back to Alice's contract. After a week, while Alice's contract has no DBR deficit, a replenisher notices that Bob's contract has a DBR deficit and wants to force it to replenish DBR. Yet, Bob notices the replenisher'sforceReplenish
transaction in the mempool and front-runs it by having his contract to send one transaction that includes therepay
andwithdraw
function calls with a higher gas fee. After the front-running, the replenisher'sforceReplenish
transaction reverts, and the debt of Bob's contract is not increased. As a result, Bob's contract is able to withdraw all of his deposited collateral while being able to utilize the borrowed DOLA for 1 week without holding any DBR at the beginning. Through sharing DBR, a user who does not really own any DBR can borrow DOLA, which is unfair to the users who actually own DBR.https://github.com/code-423n4/2022-10-inverse/blob/main/src/DBR.sol#L170-L178
https://github.com/code-423n4/2022-10-inverse/blob/main/src/DBR.sol#L188-L202
https://github.com/code-423n4/2022-10-inverse/blob/main/src/Market.sol#L408-L410
https://github.com/code-423n4/2022-10-inverse/blob/main/src/Market.sol#L389-L401
https://github.com/code-423n4/2022-10-inverse/blob/main/src/Market.sol#L559-L572
https://github.com/code-423n4/2022-10-inverse/blob/main/src/Market.sol#L531-L539
https://github.com/code-423n4/2022-10-inverse/blob/main/src/Market.sol#L472-L474
https://github.com/code-423n4/2022-10-inverse/blob/main/src/Market.sol#L460-L466
Proof of Concept
Please add the following test in
src\test\Market.t.sol
. This test will pass to demonstrate the described scenario.Tools Used
VSCode
Recommended Mitigation Steps
One way to mitigate this risk is to disallow the
DolaBorrowingRights
contract'stransfer
andtransferFrom
functions from being called whenlastUpdated[user] == block.timestamp
is true so such functions cannot be called after theMarket
contract'sborrowInternal
function is called in the same transaction.