Taiko - blockdev's results

A based rollup -- inspired, secured, and sequenced by Ethereum.

General Information

Platform: Code4rena

Start Date: 04/03/2024

Pot Size: $140,000 USDC

Total HM: 19

Participants: 69

Period: 21 days

Judge: 0xean

Total Solo HM: 4

Id: 343

League: ETH

Taiko

Findings Distribution

Researcher Performance

Rank: 17/69

Findings: 1

Award: $1,237.18

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: Shield

Also found by: blockdev, monrel

Labels

bug
2 (Med Risk)
downgraded by judge
satisfactory
:robot:_09_group
duplicate-274

Awards

1237.1813 USDC - $1,237.18

External Links

Lines of code

https://github.com/code-423n4/2024-03-taiko/blob/main/packages/protocol/contracts/L1/libs/LibProposing.sol#L307-L316

Vulnerability details

Impact

First block after genesis will never be proposed if the same address doesn't have both proposer_one and proposer role. If proposer_one is unset (address(0)), then this block can be proposed only if proposer role is also unset, or if proposer address proposes the block which is not the purpose of this role.

Proof of Concept

https://github.com/code-423n4/2024-03-taiko/blob/main/packages/protocol/contracts/L1/libs/LibProposing.sol#L307-L316

function _isProposerPermitted(
    TaikoData.SlotB memory _slotB,
    IAddressResolver _resolver
)
    private
    view
    returns (bool)
{
    if (_slotB.numBlocks == 1) {
        // Only proposer_one can propose the first block after genesis
        address proposerOne = _resolver.resolve("proposer_one", true);
        if (proposerOne != address(0) && msg.sender != proposerOne) {
            return false;
        }
    }

    address proposer = _resolver.resolve("proposer", true);
    return proposer == address(0) || msg.sender == proposer;
}

Here if proposerOne address is correctly proposing the first block after genesis, the following condition is false:

if (proposerOne != address(0) && msg.sender != proposerOne) {

The code then checks msg.sender against proposer role. What instead should have happened was, if msg.sender is proposerOne, it should just return true.

Tools Used

Manual.

Update the above code block to:

function _isProposerPermitted(
    TaikoData.SlotB memory _slotB,
    IAddressResolver _resolver
)
    private
    view
    returns (bool)
{
    address proposer;
    if (_slotB.numBlocks == 1) {
        // Only proposer_one can propose the first block after genesis
        proposer = _resolver.resolve("proposer_one", true);
    } else {
        proposer = _resolver.resolve("proposer", true);
    }

    return proposer == address(0) || msg.sender == proposer;
}

If the intention is to fallback on proposer role if proposerOne is set to address(0), then this should be used:

function _isProposerPermitted(
    TaikoData.SlotB memory _slotB,
    IAddressResolver _resolver
)
    private
    view
    returns (bool)
{
    if (_slotB.numBlocks == 1) {
        // Only proposer_one can propose the first block after genesis
        address proposerOne = _resolver.resolve("proposer_one", true);
-       if (proposerOne != address(0) && msg.sender != proposerOne) {
-           return false;
+       if (proposerOne != address(0)) {
+           return msg.sender == proposerOne;
        }
    }

    address proposer = _resolver.resolve("proposer", true);
    return proposer == address(0) || msg.sender == proposer;
}

Assessed type

Access Control

#0 - c4-pre-sort

2024-03-27T23:43:10Z

minhquanym marked the issue as duplicate of #274

#1 - c4-judge

2024-04-10T11:35:26Z

0xean changed the severity to 2 (Med Risk)

#2 - c4-judge

2024-04-10T11:35:30Z

0xean marked the issue as satisfactory

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