Connext Amarok contest - cloudjunky's results

The interoperability protocol of L2 Ethereum.

General Information

Platform: Code4rena

Start Date: 08/06/2022

Pot Size: $115,000 USDC

Total HM: 26

Participants: 72

Period: 11 days

Judge: leastwood

Total Solo HM: 14

Id: 132

League: ETH

Connext

Findings Distribution

Researcher Performance

Rank: 10/72

Findings: 2

Award: $2,739.99

🌟 Selected for report: 1

🚀 Solo Findings: 1

Findings Information

🌟 Selected for report: cloudjunky

Labels

bug
2 (Med Risk)
resolved
sponsor confirmed

Awards

2598.127 USDC - $2,598.13

External Links

Lines of code

https://github.com/code-423n4/2022-06-connext/blob/main/contracts/contracts/core/connext/facets/PortalFacet.sol#L80

Vulnerability details

Impact

When repaying the AAVE Portal in repayAavePortal() the _local asset is used to repay the loan in _backLoan() rather than the adopted asset. This is likely to cause issues in production when actually repaying loans if the asset/token being repayed to AAVE is not the same as the asset/token that was borrowed.

Proof of Concept

The comment on L93 of PortalFacet.sol states;

// Need to swap into adopted asset or asset that was backing the loan // The router will always be holding collateral in the local asset while the loaned asset // is the adopted asset

The swap is executed on L98 in the call to AssetLogic.swapFromLocalAssetIfNeededForExactOut() however the return value adopted is never used (it's an unused local variable). The full function is shown below;

// Swap for exact `totalRepayAmount` of adopted asset to repay aave (bool success, uint256 amountIn, address adopted) = AssetLogic.swapFromLocalAssetIfNeededForExactOut( _local, totalAmount, _maxIn ); if (!success) revert PortalFacet__repayAavePortal_swapFailed(); // decrement router balances unchecked { s.routerBalances[msg.sender][_local] -= amountIn; } // back loan _backLoan(_local, _backingAmount, _feeAmount, _transferId);

The balance of the _local token is reduced but instead of the adopted token being passed to _backLoan() in L112 the _local token is used.

Tools Used

Vim

To be consistent with the comments in the repayAavePortal() function adopted should be passed to _backLoan so that the loan is repayed in the appropriate token.

Remove the reference to _local in the _backLoan() function and replace it with adopted so it reads;

_backLoan(adopted, _backingAmount, _feeAmount, _transferId);

#0 - 0xleastwood

2022-08-15T09:07:38Z

If routers are able to repay Aave debt using a token of higher denomination (i.e. pay USDC debt using ETH or DAI), then the liquidity portal functionality will be broken until Connext applies the necessary protocol upgrade to become solvent again.

Considering the fact that only whitelisted routers have access to this feature and the bridge transfers are not broken but instead limited, I think medium severity makes sense.

Require with empty error messages

Issue

Multicall.solL18 has a require statement with an empty message - providing no reason as to why it might revert;

function aggregate(Call[] memory calls) public returns (uint256 blockNumber, bytes[] memory returnData) { blockNumber = block.number; returnData = new bytes[](calls.length); for (uint256 i = 0; i < calls.length; i++) { (bool success, bytes memory ret) = calls[i].target.call(calls[i].callData); require(success); returnData[i] = ret; } }

Remediation

Ensure that each require statement has a clear message for why it failed.

Incomplete natspec documentation or missing params

Issue

The following natspec comments have missing params or incomplete documentation;

Remediation

Complete natspec documentation for functions and events identified above. I tried not to be pedantic here and focused only on functions that had some form of natspec param documentation assuming they were important and more accurate documentation would help.

Unused local variables

Issue

Remediation

  1. The nonce or _nonce value is is passed to numerous handle() functions throughout the code base sufficing the IMessageRecipient{} interface. However there seems to be no requirement for it in BridgeFacet.sol and it should be documented as unused similar to the Nomad GovernanceRouter.sol handle() function i.e. uint32, // nonce (unused).
  2. _reconcileProcessPortal() is called within the _reconcile() function in BridgeFacet.sol. The first router in the path is passed to the function _reconcileProcessPortal(amount, token, routers[0], transferId);. If reconciling portal payments is not related to the router that took on the credit risk then remove routers[0] from the _reconcile() function and from the _reconcileProcessPortal() function definition.
  3. The comment suggests this is more of an issue than just an unused local variable (I'll raise this as a medium bug). However for this Q&A report suffice to say that either the variable should be ommitted with (bool success, uint256 amountIn, _) = AssetLogic.swapFromLocalAssetIfNeededForExactOut(.. or the medium bug is true and adopted should be used instead of _local for the rest of the function.
  4. _router should either be used in the function body or removed.

#0 - jakekidd

2022-07-01T22:39:31Z

1 is invalid, multicall not in scope

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