The Graph L2 bridge contest - ladboy233's results

A protocol for indexing and querying blockchain data.

General Information

Platform: Code4rena

Start Date: 07/10/2022

Pot Size: $50,000 USDC

Total HM: 4

Participants: 62

Period: 5 days

Judge: 0xean

Total Solo HM: 2

Id: 169

League: ETH

The Graph

Findings Distribution

Researcher Performance

Rank: 2/62

Findings: 2

Award: $5,676.97

🌟 Selected for report: 1

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: ladboy233

Also found by: csanuragjain

Labels

bug
2 (Med Risk)
resolved
sponsor confirmed
edited-by-warden
selected for report

Awards

5626.6867 USDC - $5,626.69

External Links

Lines of code

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/l2/gateway/L2GraphTokenGateway.sol#L87 https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/l2/token/L2GraphToken.sol#L48 https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/gateway/L1GraphTokenGateway.sol#L99 https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/gateway/BridgeEscrow.sol#L20

Vulnerability details

Impact

initialize function in L2GraphToken.sol, BridgeEscrow.sol, L2GraphTokenGateway.sol, L1GraphTokenGateway.sol

can be invoked multiple times from the implementation contract.

this means a compromised implementation can reinitialize the contract above and

become the owner to complete the privilege escalation then drain the user's fund.

Usually in Upgradeable contract, a initialize function is protected by the modifier

 initializer

to make sure the contract can only be initialized once.

Proof of Concept

Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.

  1. The implementation contract is compromised,

  2. The attacker reinitialize the BridgeEscrow contract

function initialize(address _controller) external onlyImpl { Managed._initialize(_controller); }

the onlyGovernor modifier's result depends on the controller because

    function _onlyGovernor() internal view {
        require(msg.sender == controller.getGovernor(), "Caller must be Controller governor");
    }
  1. The attacker have the governor access to the BridgeEscrow,

  2. The attack can call the approve function to approve malicious contract

     function approveAll(address _spender) external onlyGovernor {
        graphToken().approve(_spender, type(uint256).max);
    }
  1. The attack can drain all the GRT token from the BridgeEscrow.

Tools Used

Manual Review

We recommend the project use the modifier

 initializer

to protect the initialize function from being reinitiated

   function initialize(address _owner) external onlyImpl initializer  {

#0 - 0xean

2022-10-16T13:58:37Z

Sponsor - please also review #72 which is a duplicate but has a slightly different impact statement to the same underlying issue.

#1 - pcarranzav

2022-10-18T14:41:07Z

The impact from #72 was discussed with a warden and I consider it valid and worth fixing.

The impact from this one requires the implementation to be compromised in a way that allows calling initialize(). Since all implementations use GraphUpgradeable, I don't see how that's possible without also compromising the GraphProxyAdmin and therefore compromising the governor, which would mean much bigger problems.

I still consider this risky enough that a Medium severity is reasonable, both in #72 and this one.

#2 - trust1995

2022-10-18T21:10:37Z

Exploit of this bug requires ProxyAdmin compromise, and if attacker has that then there are many ways to severely damage the proxy. It's a good observation and should be fixed, but it seems to be a best practice issue.

#3 - pcarranzav

2022-10-21T17:09:36Z

#4 - 0xean

2022-10-21T21:36:57Z

@trust1995 - makes reasonable points, but I think its still correct to award this as M.

#5 - trust1995

2022-10-25T06:57:25Z

Would like to restate my strong opinion that this is not a vulnerability but a best practice issue. The only way to abuse the lack of "initializer" modifier is with ProxyAdmin calling the IMPL contract. But it is known ProxyAdmin can just change the IMPL contract to any it desires. The risk of ProxyAdmin being compromised is a generic centralization issue, applicable to every upgradeable structure and is far too much of a known risk to qualify as M.

As further evidence, 5 QA reports categorized the find as Low / QA. They also should be upgraded to M, or this report rightfully moved to QA / Low.

Awards

50.2765 USDC - $50.28

Labels

bug
QA (Quality Assurance)
edited-by-warden

External Links

transferFrom return value not handled

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/gateway/L1GraphTokenGateway.sol#L235

                token.transferFrom(from, escrow, _amount);

Use __ERC20Burnable_init instead of __ERC20_init in GraphTokenUpgradeable.sol

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/l2/token/GraphTokenUpgradeable.sol#L151

The contract GraphTokenUpgradeable.sol inherits

ERC20BurnableUpgradeable

contract GraphTokenUpgradeable is GraphUpgradeable, Governed, ERC20BurnableUpgradeable {

however, the function

  __ERC20_init

is called,

we recommend the project change the call to

  __ERC20Burnable_init

Use updated openzeppelin version

The openzeppelin version used is outdated.

    "@openzeppelin/contracts": "^3.4.1",
    "@openzeppelin/contracts-upgradeable": "3.4.2",

Use updated solidity version

The updated solidity version is 0.8.17

https://soliditylang.org/

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/gateway/BridgeEscrow.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/upgrades/GraphUpgradeable.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/governance/Governed.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/governance/Pausable.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/l2/token/L2GraphToken.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/upgrades/GraphProxyAdmin.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/upgrades/GraphProxyStorage.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/upgrades/GraphProxy.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/governance/IManaged.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/l2/token/GraphTokenUpgradeable.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/l2/gateway/L2GraphTokenGateway.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/l2/gateway/L2GraphTokenGateway.sol#L4

pragma abicoder v2;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/gateway/L1GraphTokenGateway.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/gateway/GraphTokenGateway.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/curation/IGraphCurationToken.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/gateway/ICallhookReceiver.sol#L9

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/upgrades/IGraphProxy.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/epochs/IEpochManager.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/governance/IController.sol#L3

pragma solidity >=0.6.12 <0.8.0;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/token/IGraphToken.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/rewards/IRewardsManager.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/staking/IStakingData.sol#L3

pragma solidity >=0.6.12 <0.8.0;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/curation/ICuration.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/staking/IStaking.sol#L3

pragma solidity >=0.6.12 <0.8.0;

NON-LIBRARY/INTERFACE FILES SHOULD USE FIXED COMPILER VERSIONS, NOT FLOATING ONES

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/gateway/BridgeEscrow.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/upgrades/GraphUpgradeable.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/governance/Governed.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/governance/Pausable.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/l2/token/L2GraphToken.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/upgrades/GraphProxyAdmin.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/upgrades/GraphProxyStorage.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/upgrades/GraphProxy.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/governance/IManaged.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/l2/token/GraphTokenUpgradeable.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/l2/gateway/L2GraphTokenGateway.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/gateway/L1GraphTokenGateway.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/gateway/GraphTokenGateway.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/curation/IGraphCurationToken.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/gateway/ICallhookReceiver.sol#L9

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/upgrades/IGraphProxy.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/epochs/IEpochManager.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/token/IGraphToken.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/rewards/IRewardsManager.sol#L3

pragma solidity ^0.7.6;

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/curation/ICuration.sol#L3

pragma solidity ^0.7.6;

require statement does not have reason of failure

User will not know which steps goes wrong when transaction reverted.

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/governance/Governed.sol#L54

        require(

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/upgrades/GraphProxyAdmin.sol#L34

        require(success);

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/upgrades/GraphProxyAdmin.sol#L47

        require(success);

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/upgrades/GraphProxyAdmin.sol#L59

        require(success);

https://github.com/code-423n4/2022-10-thegraph/blob/309a188f7215fa42c745b136357702400f91b4ff/contracts/upgrades/GraphProxy.sol#L133

        require(success);

#0 - pcarranzav

2022-10-19T17:40:52Z

Use __ERC20Burnable_init instead of __ERC20_init in GraphTokenUpgradeable.sol

I checked and __ERC20Burnable_init does not call __ERC20_init afaict, so we do need to call __ERC20_init.

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