Axelar Network v2 contest - Lambda's results

Decentralized interoperability network.

General Information

Platform: Code4rena

Start Date: 29/07/2022

Pot Size: $50,000 USDC

Total HM: 6

Participants: 75

Period: 5 days

Judge: GalloDaSballo

Total Solo HM: 3

Id: 149

League: ETH

Axelar Network

Findings Distribution

Researcher Performance

Rank: 4/75

Findings: 5

Award: $7,710.47

🌟 Selected for report: 3

πŸš€ Solo Findings: 0

Findings Information

🌟 Selected for report: Lambda

Also found by: 0x52, cryptphi

Labels

bug
2 (Med Risk)
sponsor confirmed

Awards

2078.8043 USDC - $2,078.80

External Links

Lines of code

https://github.com/code-423n4/2022-07-axelar/blob/a1205d2ba78e0db583d136f8563e8097860a110f/xc20/contracts/XC20Wrapper.sol#L66

Vulnerability details

Impact

An owner can call removeWrapping, even if there are still circulating wrapped tokens. This will cause the unwrapping of those tokens to fail, as unwrapped[wrappedToken] will be addres(0).

Track how many wrapped tokens are in circulation, only allow the removal of a wrapped tokens when there are 0 to ensure for users that they will always be able to unwrap.

#0 - re1ro

2022-08-05T01:12:46Z

Valid observation. We will consider a different approach.

Mitigation

removeWrapping method was removed https://github.com/axelarnetwork/axelar-xc20-wrapper/pull/4

#1 - GalloDaSballo

2022-08-28T23:11:38Z

The warden has shown how, the Admin can remove the mapping that allows to redeem bridged tokens, because this will cause the inability to unwrap, and can be operated by the admin, I agree with Medium Severity.

The sponsor has confirmed and they have mitigated by removing the function

Findings Information

🌟 Selected for report: Lambda

Also found by: Chom

Labels

bug
2 (Med Risk)
sponsor acknowledged

Awards

3464.6739 USDC - $3,464.67

External Links

Lines of code

https://github.com/code-423n4/2022-07-axelar/blob/a46fa61e73dd0f3469c0263bc6818e682d62fb5f/contracts/deposit-service/DepositReceiver.sol#L25

Vulnerability details

Impact

After EIP-4758, the SELFDESTRUCT op code will no longer be available. According to the EIP, "The only use that breaks is where a contract is re-created at the same address using CREATE2 (after a SELFDESTRUCT)". Axelar is exactly such an application, the current deposit system will no longer work.

To avoid that Axelar simply stops working one day, the architecture should be changed. Instead of generating addresses for every user, the user could directly interact with the deposit service and the deposit service would need to keep track of funds and provide refunds directly.

#0 - re1ro

2022-08-05T01:00:15Z

Very good spot. We will address this

#1 - GalloDaSballo

2022-09-04T19:20:44Z

The warden has shown a plausible upgrade path for Ethereum that will remove the SELFDESTRUCT opcode, bricking the DepositReceiver functionality.

If the fork was in place today, the code would be broken, and the finding should be of high severity.

Because the fork is not in place, and no clear timeline is defined for "The Purge", I think Medium Severity to be correct

Findings Information

🌟 Selected for report: Lambda

Also found by: Respx, Ruhum

Labels

bug
2 (Med Risk)
disagree with severity
sponsor confirmed

Awards

2078.8043 USDC - $2,078.80

External Links

Lines of code

https://github.com/code-423n4/2022-07-axelar/blob/3373c48a71c07cfce856b53afc02ef4fc2357f8c/contracts/AxelarGateway.sol#L268 https://github.com/code-423n4/2022-07-axelar/blob/3373c48a71c07cfce856b53afc02ef4fc2357f8c/contracts/AxelarGateway.sol#L311

Vulnerability details

Impact

According to the specifications, only the current operators should be able to transfer operatorship. However, there is one way to circumvent this. Because currentOperators is not updated in the loop, when multiple transferOperatorship commands are submitted in the same execute call, all will succeed. After the first one, the operators that signed these commands are no longer the current operators, but the call will still succeed.

This also means that one set of operators could submit so many transferOperatorship commands in one execute call that OLD_KEY_RETENTION is reached for all other ones, meaning they would control complete set of currently valid operators.

Set currentOperators to false when the operators were changed.

#0 - re1ro

2022-08-05T00:58:46Z

This case would never occur in practice because our command batches are produced and signed by the Axelar nerwork. So there would be never 2 transferOperatorship commands in the same batch.

In general if the recent operators turn malicious they can overtake the gateway disregarding this finding.

Mitigation

We still have added the sanity check to set currentOperators to false. https://github.com/axelarnetwork/axelar-cgp-solidity/pull/138

#1 - milapsheth

2022-08-24T17:51:09Z

For more context, the current operators could just easily transfer the operatorship in multiple txs instead. We heavily rely on the assumption the majority of the operators by weight are not malicious.

#2 - GalloDaSballo

2022-09-04T19:18:26Z

Very interesting find.

Per the warden submission: the operators can sign a transferOperatorship and then still act as if they are the current operator while their calls are being executed.

This can be further extended to perform more than OLD_KEY_RETENTION to invalidate all old keys, which may be desirable or a malicious attack depending on context.

The sponsor disagrees with severity, citing that the main assumption of the code is that operators by weight are non malicious

Personally I think the finding:

  • Breaks an assumption of the code (current operators exclusively can transferOperatorship)
  • Allows the operators to kick old operators in one tx instead of OLD_KEY_RETENTION txs

#3 - GalloDaSballo

2022-09-04T23:55:06Z

With the information that I have, considering that:

  • Breaks an assumption of the code (current operators exclusively can transferOperatorship)
  • Allows the operators to kick old operators in one tx instead of OLD_KEY_RETENTION txs

Because this is contingent on a malicious majority, and considering that a malicious majority can perform even worse attacks (DOS, TX Censoring, Shutting down the chain)

I believe that Medium Severity is correct

Lines of code

https://github.com/code-423n4/2022-07-axelar/blob/a46fa61e73dd0f3469c0263bc6818e682d62fb5f/contracts/deposit-service/ReceiverImplementation.sol#L23 https://github.com/code-423n4/2022-07-axelar/blob/a46fa61e73dd0f3469c0263bc6818e682d62fb5f/contracts/deposit-service/ReceiverImplementation.sol#L51 https://github.com/code-423n4/2022-07-axelar/blob/a46fa61e73dd0f3469c0263bc6818e682d62fb5f/contracts/deposit-service/ReceiverImplementation.sol#L71 https://github.com/code-423n4/2022-07-axelar/blob/a46fa61e73dd0f3469c0263bc6818e682d62fb5f/contracts/deposit-service/ReceiverImplementation.sol#L86 https://github.com/code-423n4/2022-07-axelar/blob/3373c48a71c07cfce856b53afc02ef4fc2357f8c/contracts/gas-service/AxelarGasService.sol#L128 https://github.com/code-423n4/2022-07-axelar/blob/3373c48a71c07cfce856b53afc02ef4fc2357f8c/contracts/gas-service/AxelarGasService.sol#L144 https://github.com/code-423n4/2022-07-axelar/blob/a1205d2ba78e0db583d136f8563e8097860a110f/xc20/contracts/XC20Wrapper.sol#L63

Vulnerability details

Impact

The system uses transfer which only has a 2300 gas stipend in various places for transferring ETH. Depending on the logic of the retriever (e.g., a smart contract that performs some storage read and writes on receive, for instance a multi-sig), this may not be sufficient and the transfer can revert. See also https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/ for a discussion of this issue.

Use call instead, e.g.:

(bool success, ) = payable(payAddress).call{amount}(""); require(success, "Transfer failed.");

#0 - re1ro

2022-08-05T01:00:46Z

Duplicate of #4

./auth/AxelarAuthWeighted.sol: for (uint256 i; i < recentOperators.length; ++i) { ./auth/AxelarAuthWeighted.sol: for (uint256 i = 0; i < weightsLength; ++i) { ./auth/AxelarAuthWeighted.sol: for (uint256 i = 0; i < signatures.length; ++i) { ./auth/AxelarAuthWeighted.sol: for (; operatorIndex < operatorsLength && signer != operators[operatorIndex]; ++operatorIndex) {} ./auth/AxelarAuthWeighted.sol: for (uint256 i; i < accounts.length - 1; ++i) { ./gas-service/AxelarGasService.sol: for (uint256 i; i < tokens.length; i++) { ./deposit-service/AxelarDepositService.sol: for (uint256 i; i < refundTokens.length; i++) { ./deposit-service/AxelarDepositService.sol: for (uint256 i; i < refundTokens.length; i++) { ./deposit-service/AxelarDepositService.sol: for (uint256 i; i < refundTokens.length; i++) {

#0 - re1ro

2022-08-05T00:57:40Z

1

Good spot

2

Dup #2

#1 - GalloDaSballo

2022-08-23T00:51:49Z

In refundTokenDeposit within AxelarDepositService

Will save 100 gas per instance

Unchecked

20 per instance

280 gas saved in total, rounding up to 300

#2 - re1ro

2022-08-23T01:15:16Z

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