Livepeer contest - Ruhum's results

Decentralized live streaming platform built on the blockchain.

General Information

Platform: Code4rena

Start Date: 13/01/2022

Pot Size: $75,000 USDC

Total HM: 9

Participants: 27

Period: 7 days

Judge: leastwood

Total Solo HM: 5

Id: 73

League: ETH

Livepeer

Findings Distribution

Researcher Performance

Rank: 4/27

Findings: 6

Award: $4,987.89

🌟 Selected for report: 2

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: WatchPug

Also found by: Ruhum, gzeon, harleythedog

Labels

bug
duplicate
3 (High Risk)

Awards

20.7302 LPT - $768.68

2113.9229 USDC - $2,113.92

External Links

Handle

Ruhum

Vulnerability details

Impact

The L1Migrator.migrateETH() function can be called by anyone. It pulls all the ETH from the BridgeMinter contract and starts the process of moving the funds to L2. First of all, this function is only executable once. The RetryableTicket created with the first call is the only chance of moving the funds to L2.

The attacker can call the function with parameters that make the creation of the RetryableTicket on L2 fail. Thus, the ETH sits in the L1Migrator contract with no way of moving it to L2 or anywhere else. Effectively, the funds are lost.

Proof of Concept

The function is only executable once because it uses the amount returned by IBridgeMinter(bridgeMinterAddr).withdrawETHToL1Migrator() to specify the amount of ETH to be sent to L2: https://github.com/livepeer/arbitrum-lpt-bridge/blob/main/contracts/L1/gateway/L1Migrator.sol#L308

After the first call to migrateETH() that function will always return 0 since the BridgeMinter won't have any more ETH: https://github.com/livepeer/protocol/blob/streamflow/contracts/token/BridgeMinter.sol#L91

So after the attacker called migrateETH() with insufficient funds to create a RetryableTicket on L2 we have the following state:

  • BridgeMinter has 0 ETH
  • L1Migrator has X amount of ETH that is not accessible. There are no functions to get the ETH out of there.
  • 1 failed RetryTicket

The same thing can also be triggered by a non-malicious caller by simply providing insufficient funds. The whole design of only being able to try once is the issue here.

Tools Used

none

Instead of using the amount returned by IBridgeMinter(bridgeMinterAddr).withdrawETHToL1Migrator() you should use the balance of the L1Migrator contract.

It might also make sense to not allow anybody to call the function. I don't see the benefit of that.

#0 - yondonfu

2022-01-23T13:56:18Z

Findings Information

🌟 Selected for report: Ruhum

Also found by: gzeon, harleythedog

Labels

bug
2 (Med Risk)
resolved
sponsor confirmed

Awards

9.2134 LPT - $341.63

939.5213 USDC - $939.52

External Links

Handle

Ruhum

Vulnerability details

Vulnerability details

Impact

Same thing as the ETH issue I reported earlier. I wasn't sure if those are supposed to be a single issue or not. The concept is the same. But, now you lose LPT tokens.

The L1Migrator.migrateLPT() function can be called by anyone. It pulls all the LPT from the BridgeMinter contract and starts the process of moving the funds to L2. First of all, this function is only executable once. The RetryableTicket created with the first call is the only chance of moving the funds to L2.

The attacker can call the function with parameters that make the creation of the RetryableTicket on L2 fail. Thus, the LPT sits in the L1Migrator contract with no way of moving it to L2 or anywhere else. Effectively, the funds are lost.

Proof of Concept

The function is only executable once because it uses the amount returned by IBridgeMinter(bridgeMinterAddr).withdrawLPTToL1Migrator() to specify the amount of LPT to be sent to L2: https://github.com/livepeer/arbitrum-lpt-bridge/blob/main/contracts/L1/gateway/L1Migrator.sol#L342

After the first call to migrateLPT() that function will always return 0 since the BridgeMinter won't have any more LPT: https://github.com/livepeer/protocol/blob/streamflow/contracts/token/BridgeMinter.sol#L107

So after the attacker called migrateLPT() with insufficient funds to create a RetryableTicket on L2 we have the following state:

  • BridgeMinter has 0 LPT
  • L1Migrator has X amount of LPT that is not accessible. There are no functions to get the LPT out of there.
  • 1 failed RetryTicket

The same thing can also be triggered by a non-malicious caller by simply providing insufficient funds. The whole design of only being able to try once is the issue here.

Tools Used

none

Instead of using the amount returned by IBridgeMinter(bridgeMinterAddr).withdrawLPTToL1Migrator() you should use the balance of the L1Migrator contract.

It might also make sense to not allow anybody to call the function. I don't see the benefit of that.

EDIT Actually, the funds aren't lost. The funds are sent to the Escrow contract which can be used to transfer the funds back to the BridgeMinter contract. Thus, you could reset the whole thing to its initial state and call L1Migrator.migrateLPT() again. But, a really persistent attacker has the ability to DoS the function by frontrunning any call to it which results in the RetryableTicket failing again. Thus, you'd have to transfer the funds from the Escrow contract to the BrigeMinter again and so on.

So the same scenario I've outlined earlier is still viable. It's just a bit more difficult now since it has a higher cost for the attacker now. Because of that I think it's an medium issue instead of high.

Also, the mitigation steps I've given aren't valid. You can't use the L1Migrator contract's balance since it will always be 0 (the funds are sent to the Escrow contract). Thus the best solution would be to just limit the access to the function.

#0 - itsmetechjay

2022-01-18T14:15:42Z

Per Ruhum, "I'd like to reduce the severity to medium and add the comment included in the EDIT section"

#1 - 0xleastwood

2022-01-29T23:48:08Z

Nice find! The warden has outlined a potential DOS attack which can lead to funds lost which are only recoverable by the transferring the funds in the escrow contract back to the bridge minter contract.

Findings Information

🌟 Selected for report: Ruhum

Labels

bug
G (Gas Optimization)
sponsor acknowledged

Awards

0.8082 LPT - $29.97

82.4134 USDC - $82.41

External Links

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