Decent - Greed's results

Decent enables one-click transactions using any token across chains.

General Information

Platform: Code4rena

Start Date: 19/01/2024

Pot Size: $36,500 USDC

Total HM: 9

Participants: 113

Period: 3 days

Judge: 0xsomeone

Id: 322

League: ETH

Decent

Findings Distribution

Researcher Performance

Rank: 88/113

Findings: 1

Award: $0.12

🌟 Selected for report: 0

🚀 Solo Findings: 0

Lines of code

https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DecentEthRouter.sol#L302-L310 https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DcntEth.sol#L20-L22

Vulnerability details

Impact

By exploiting this vulnerability, an attacker is able to steal all the native ETH locked in the bridge. The assets belong to legitimate users, meaning a loss of user funds, insolvency for the protocol and profit for the attacker.

The issue leading to the vulnerability can be exploited in a different way with a different impact but the following scenario is the most impactful

Proof of concept

The DecentEthRouter.sol contract stores users native ETH belonging to users using the addLiquidityEth() function.

https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DecentEthRouter.sol#L302-L310

The function redeemEth() can be used to withdraw WETH but only if the msg.sender owns the dcntEth token and has approve() the router to use it.

https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DecentEthRouter.sol#L285-L291

function redeemEth(
    uint256 amount
) public onlyIfWeHaveEnoughReserves(amount) {
    dcntEth.transferFrom(msg.sender, address(this), amount);
    weth.withdraw(amount);
    payable(msg.sender).transfer(amount);
}

The mint() function of DcntEth.sol contract is protected by the onlyRouter modifier, giving the ability to mint tokens to DecentEthRouter only.

https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DcntEth.sol#L8-L11 https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DcntEth.sol#L24-L26

modifier onlyRouter() {
    require(msg.sender == router);
    _;
}

// ...

function mint(address _to, uint256 _amount) public onlyRouter {
    _mint(_to, _amount);
}

In order to set the router address, the function setRouter() is used but as you can see, it has no access control meaning anyone can call it and become the router

https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DcntEth.sol#L20-L22

function setRouter(address _router) public {
    router = _router;
}

An attacker can set himself as the router using the setRouter() function, mint() a huge amount of tokens for himself, approve() the legitimate DecentEthRouter to spend it and call redeemEth() to steal all the ETH (converted from WETH) from the router before calling setRouter() again to set the protocol to its initial state.

The scenario exposed makes use of the redeemEth() function but the issue impacts all the functions used to retrieve funds

Tools used

Manual review

Add access control to the setRouter() function

Assessed type

ETH-Transfer

#0 - c4-pre-sort

2024-01-24T08:23:28Z

raymondfam marked the issue as sufficient quality report

#1 - c4-pre-sort

2024-01-24T08:23:38Z

raymondfam marked the issue as duplicate of #14

#2 - c4-judge

2024-02-03T13:23:29Z

alex-ppg marked the issue as satisfactory

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter