First depositor attack: first depositor can steal funds from later depositors by manipulating initial share price. #29
Labels
bug
Something isn't working
downgraded by judge
Judge downgraded the risk level of this issue
duplicate-848
edited-by-warden
grade-b
QA (Quality Assurance)
Assets are not at risk. State handling, function incorrect as to spec, issues with clarity, syntax
satisfactory
satisfies C4 submission criteria; eligible for awards
Lines of code
https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/ReaperVaultERC4626.sol#L110-L112
https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/ReaperVaultERC4626.sol#L202-L210
https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/ReaperVaultERC4626.sol#L51-L54
https://github.com/code-423n4/2023-02-ethos/blob/73687f32b934c9d697b97745356cdf8a1f264955/Ethos-Vault/contracts/ReaperVaultERC4626.sol#L66-L69
Vulnerability details
Impact
Detailed description of the impact of this finding.
First depositor can steal funds from later depositors by manipulating initial share price.
Proof of Concept
Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.
We show how the first depositor, Bob, can steal funds from later depositors by manipulating initial share price below:
_freeFunds() = 0
andtotalSupply()
, note the implementation of_freeFunds()
below. In this attack,totalAllocated
and the locked profit will be zero initially and will not change in this attack. We will only pay attention to thetoken.balanceOf(address(this))
component for the_freeFunds()
.deposit(1, Bob)
to spend 1 wei of asset token in exchange of 1 vault share. After that, we havetotalSupply()=1
, and_freeFunds() = 1
.Bob sends
(1,000*1e18)
asset tokens to theReaperVaultERC4626
contract. After that, we havetotalSupply()=1
, and_freeFunds() = 1,000*1e18+1
. Now the vault share price is inflated to (1,000*1e18+1)/share.Alice calls
Deposit(2,000*1e18, Alice)
and gets 1 vault share. After that, we havetotalSupply()=2
, and_freeFunds() = 3,000*1e18+1
. Now the vault share price is(1,500*1e18)/share
.Bob withdraws his one share by calling
redeem(1, Bob, Bob)
and he gets back1,500*1e18
asset tokens. We do not need to worry about the rest of the code afterif (value > token.balanceOf(address(this)))
since the condition is false.If Alice withdrew her vault share at this point, she would get 1,5001e18 asset tokens and lose 5001e18 asset tokens.
Bob gains 500*1e18 asset tokens, He steals it from Alice!
Tools Used
VScode
Recommended Mitigation Steps
When the vault is deployed in a factory, an honest deployer can mint 1000 shares with 1000 wei and sent them to a dead address.
Enforce a minimum 1000 shares for each deposit and automatically sends 1000 shares to a dead address from the first deposit. The amount of 1000 wei is negligible for most asset tokens.
The text was updated successfully, but these errors were encountered: