Alchemix contest - 0x1337's results

A protocol for self-repaying loans with no liquidation risk.

General Information

Platform: Code4rena

Start Date: 05/05/2022

Pot Size: $125,000 DAI

Total HM: 17

Participants: 62

Period: 14 days

Judge: leastwood

Total Solo HM: 15

Id: 120

League: ETH

Alchemix

Findings Distribution

Researcher Performance

Rank: 9/62

Findings: 1

Award: $6,389.44

🌟 Selected for report: 1

🚀 Solo Findings: 1

Findings Information

🌟 Selected for report: 0x1337

Labels

bug
2 (Med Risk)
sponsor confirmed

Awards

6389.4401 DAI - $6,389.44

External Links

Lines of code

https://github.com/code-423n4/2022-05-alchemix/blob/de65c34c7b6e4e94662bf508e214dcbf327984f4/contracts-full/AlchemicTokenV2Base.sol#L20 https://github.com/code-423n4/2022-05-alchemix/blob/de65c34c7b6e4e94662bf508e214dcbf327984f4/contracts-full/CrossChainCanonicalBase.sol#L12 https://github.com/code-423n4/2022-05-alchemix/blob/de65c34c7b6e4e94662bf508e214dcbf327984f4/contracts-full/TransmuterV2.sol#L26 https://github.com/code-423n4/2022-05-alchemix/blob/de65c34c7b6e4e94662bf508e214dcbf327984f4/contracts-full/CrossChainCanonicalAlchemicTokenV2.sol#L7

Vulnerability details

Impact

For upgradeable contracts, there must be storage gap to "allow developers to freely add new state variables in the future without compromising the storage compatibility with existing deployments" (quote OpenZeppelin). Otherwise it may be very difficult to write new implementation code. Without storage gap, the variable in child contract might be overwritten by the upgraded base contract if new variables are added to the base contract. This could have unintended and very serious consequences to the child contracts, potentially causing loss of user fund or cause the contract to malfunction completely.

Refer to the bottom part of this article: https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable

Proof of Concept

Several contracts are intended to be upgradeable contracts in the code base, including

  • AlchemicTokenV2Base
  • CrossChainCanonicalBase
  • CrossChainCanonicalAlchemicTokenV2
  • TransmuterV2

However, none of these contracts contain storage gap. The storage gap is essential for upgradeable contract because "It allows us to freely add new state variables in the future without compromising the storage compatibility with existing deployments". Refer to the bottom part of this article:

https://docs.openzeppelin.com/contracts/3.x/upgradeable

As an example, both the AlchemicTokenV2Base and the CrossChainCanonicalBase are intended to act as the base contracts in the project. If the contract inheriting the base contract contains additional variable, then the base contract cannot be upgraded to include any additional variable, because it would overwrite the variable declared in its child contract. This greatly limits contract upgradeability.

Tools Used

Manual review

Recommend adding appropriate storage gap at the end of upgradeable contracts such as the below. Please reference OpenZeppelin upgradeable contract templates.

uint256[50] private __gap;

#0 - 0xfoobar

2022-05-30T06:49:12Z

Sponsor confirmed

#1 - 0xleastwood

2022-06-12T21:05:22Z

Agree with warden and severity. Storage gaps are essential wherever inheritance is used by an upgradeable contract.

#2 - 0xleastwood

2022-07-25T20:01:45Z

I believe this to be a valid finding with the correct severity because:

  • The contracts cannot be upgraded without breaking storage compatibility.
  • Because upgradeability is vital to quickly adapting to issues and improvements in the codebase, it seems likely that an upgrade may unintentionally break other parts of the contract.

For these reasons, I think medium severity to be justified.

#3 - 0xleastwood

2022-07-25T20:26:46Z

In this issue, context is important. This would have been downgraded to QA in two scenarios:

  • Only one of the affected contracts was used in inheritance at a given time. Hence, there is no concern for slot collisions as state variables are simply appended.
  • More than one upgradeable contract is inherited but the entire state is held under a single storage contract. Slot collisions are only possible if the project decides to add storage variables to other contracts. Because this goes against the intended architectural design, this seems like an abuse of the correct standard.

In the case of Alchemix, CrossChainCanonicalAlchemicTokenV2.sol inherits CrossChainCanonicalBase.sol and AlchemicTokenV2Base.sol which both contain storage variables. Any upgrade to CrossChainCanonicalBase.sol would overwrite storage in AlchemicTokenV2Base.sol.

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