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
Rank: 57/113
Findings: 2
Award: $23.19
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: NPCsCorp
Also found by: 0x11singh99, 0xAadi, 0xBugSlayer, 0xE1, 0xPluto, 0xSimeon, 0xSmartContract, 0xabhay, 0xdice91, 0xprinc, Aamir, Aymen0909, CDSecurity, DadeKuma, DarkTower, EV_om, Eeyore, GeekyLumberjack, GhK3Ndf, Giorgio, Greed, Inference, JanuaryPersimmon2024, Kaysoft, Krace, Matue, MrPotatoMagic, NentoR, Nikki, PUSH0, Soliditors, Tendency, Tigerfrake, Timeless, Timenov, ZanyBonzy, ZdravkoHr, abiih, adeolu, al88nsk, azanux, bareli, boredpukar, cu5t0mpeo, d4r3d3v1l, darksnow, deth, dutra, ether_sky, haxatron, ke1caM, kodyvim, m4ttm, mgf15, mrudenko, nmirchev8, nobody2018, nuthan2x, peanuts, piyushshukla, ravikiranweb3, rouhsamad, seraviz, simplor, slylandro_star, stealth, th13vn, vnavascues, wangxx2026, zaevlad
0.1172 USDC - $0.12
The identified issue in the setRouter
function represents a critical security vulnerability due to the absence of proper access control. As the function stands, any user can change the router address, granting them the ability to mint and burn DcntEth tokens. This lack of access control could lead to unauthorized manipulation of the protocol, posing a severe threat to the integrity of the system and potential financial losses for the protocol and users.
The issue is evident in the setRouter
function provided below:
function setRouter(address _router) public { //@audit Lack of access control: anyone can change the router address router = _router; }
As it can be seen any user can change the router address and set it to any other address (even his own wallet) which will allow him to call mint
and burn
to mint or burn DcntEth tokens, this is supposed to be done only by the true router.
This issue will result in unauthorized minting of DcntEth tokens which will affect the protocol working and cause financial losses.
Manual review
To address this issue, implement proper access control by adding the onlyOwner
modifier to the setRouter
function.
Access Control
#0 - c4-pre-sort
2024-01-25T05:23:16Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2024-01-25T05:23:22Z
raymondfam marked the issue as duplicate of #14
#2 - c4-judge
2024-02-03T13:09:49Z
alex-ppg marked the issue as satisfactory
23.067 USDC - $23.07
https://github.com/code-423n4/2024-01-decent/blob/main/src/UTB.sol#L311-L319 https://github.com/code-423n4/2024-01-decent/blob/main/src/UTB.sol#L108-L125
Any user can call the receiveFromBridge
function to perform a swap & execute without paying the protocol fees, the receiveFromBridge
function allows the users to invoke _swapAndExecute
without the processing of fees through the retrieveAndCollectFees
modifier that it's present in the swapAndExecute
function. Basically the fees can be bypassed by calling receiveFromBridge
instead of swapAndExecute
resulting in a financial loss for the protocol.
The swapAndExecute
function allows a user to swap currency from the incoming to the outgoing token and executes a transaction with that payment, in the process the user must also pay a protocol fee which is handled by the retrieveAndCollectFees
modifier :
function swapAndExecute( SwapAndExecuteInstructions calldata instructions, FeeStructure calldata fees, bytes calldata signature ) public payable retrieveAndCollectFees(fees, abi.encode(instructions, fees), signature) { _swapAndExecute( instructions.swapInstructions, instructions.target, instructions.paymentOperator, instructions.payload, instructions.refund ); }
As it can be seen the function internally invokes _swapAndExecute
for handling the swap & execution logic.
The issue now is that there is another function that also internally invokes _swapAndExecute
which is the receiveFromBridge
function:
function receiveFromBridge( SwapInstructions memory postBridge, address target, address paymentOperator, bytes memory payload, address payable refund ) public { //@audit callable by anyone _swapAndExecute(postBridge, target, paymentOperator, payload, refund); }
The function is public so it's callable by anyone to perform a swap and execute a tx but this function doesn't include the retrieveAndCollectFees
modifier as in swapAndExecute
and so it doesn't charge fees when it's called.
In normal situations the receiveFromBridge
function should only be called by the approved bridge adapters (registered by the owner) but because there is no check for that the caller is really a bridge adapter, any user can use the function instead of swapAndExecute
to bypass the fees while running his swap transaction.
Manual review
Update the receiveFromBridge
function to incorporate proper access control allowing only approved bridge adapters as caller, the following check could be added:
function receiveFromBridge( SwapInstructions memory postBridge, address target, address paymentOperator, bytes memory payload, address payable refund ) public { //@audit callable only by bridge adapters require(bridgeAdapters[IBridgeAdapter(msg.sender).getId()] != address(0), "not bridge adapter"); _swapAndExecute(postBridge, target, paymentOperator, payload, refund); }
Access Control
#0 - c4-pre-sort
2024-01-25T05:26:46Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2024-01-25T05:26:53Z
raymondfam marked the issue as duplicate of #15
#2 - c4-judge
2024-02-03T12:16:28Z
alex-ppg marked the issue as satisfactory
#3 - c4-judge
2024-02-03T13:03:51Z
alex-ppg changed the severity to 2 (Med Risk)