In the current implementation, borrow() takes a user input value of zIncrease, while the actual collateral asset transferred in is calculated at L319, the state of pool.state.z still increased by the value of the user's input at L332.
Even though a large number of zIncrease means that the user needs to add more collateral, the attacker can use a dust amount xDecrease (1 wei for example) so that the total collateral needed is rather small.
Plus, the attacker can always pay() the dust amount of loan to get back the rather large amount of collateral added.
Near the maturity time, the attacker can do the following:
borrow() a dust amount of assets (xDecrease = 1 wei) and increase pool.state.z to an extremely large value (20x of previous state.z in our tests);
pay() the loan and get back the collateral;
lend() a regular amount of state.x, get a large amount of insurance token;
burn() the insurance token and get a large portion of the collateral assets from the defaulted loans.
Recommendation
Consider making pair.borrow() to be onlyConvenience, so that zIncrease will be a computed value (based on xDecrease and current state) rather than a user input value.
Handle
WatchPug
Vulnerability details
In the current implementation,
borrow()
takes a user input value ofzIncrease
, while the actual collateral asset transferred in is calculated at L319, the state ofpool.state.z
still increased by the value of the user's input at L332.Even though a large number of
zIncrease
means that the user needs to add more collateral, the attacker can use a dust amountxDecrease
(1 wei for example) so that the total collateral needed is rather small.Plus, the attacker can always
pay()
the dust amount of loan to get back the rather large amount of collateral added.https://github.com/code-423n4/2022-01-timeswap/blob/bf50d2a8bb93a5571f35f96bd74af54d9c92a210/Timeswap/Timeswap-V1-Core/contracts/TimeswapPair.sol#L299-L338
https://github.com/code-423n4/2022-01-timeswap/blob/bf50d2a8bb93a5571f35f96bd74af54d9c92a210/Timeswap/Timeswap-V1-Core/contracts/libraries/BorrowMath.sol#L62-L79
PoC
Near the maturity time, the attacker can do the following:
borrow()
a dust amount of assets (xDecrease
= 1 wei) and increasepool.state.z
to an extremely large value (20x of previousstate.z
in our tests);pay()
the loan and get back the collateral;lend()
a regular amount ofstate.x
, get a large amount of insurance token;burn()
the insurance token and get a large portion of the collateral assets from the defaulted loans.Recommendation
Consider making
pair.borrow()
to beonlyConvenience
, so thatzIncrease
will be a computed value (based onxDecrease
and current state) rather than a user input value.