Missing freshness check in L2LPTDataCache.finalizeCacheTotalSupply leads to underpaid (or overpaid) rewards in the next rounds
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 155
- Forks
- 50
- PR merge metrics
- No merged PRs in 30d
Description
### Summary
The current implementation of the [L1LPTDataCache.cacheTotalSupply](https://github.com/livepeer/arbitrum-lpt-bridge/blob/fb75e274c28e5d4332fc177961904df67a38745d/contracts/L1/gateway/L1LPTDataCache.sol#L29-L52) and its counterpart [L2LPTDataCache.finalizeCacheTotalSupply](https://github.com/livepeer/arbitrum-lpt-bridge/blob/fb75e274c28e5d4332fc177961904df67a38745d/contracts/L2/gateway/L2LPTDataCache.sol#L81-L92) does not implement a freshness check of the received `_totalSupply` amount via a cross-chain message. This is a problem, since cross-chain messages sent via Arbitrum's native retryable tickets can fail immediate automatic redemption, but can be redeemed manually much later, when bridged `totalSupply` is severely outdated. This can, in the worst case, affect the amount of rewards delegates will receive on L2 – this number is currently used only by the Minter to determine rewards at the round start.
### Root causes
1. Preventable automatic redemption. Permissionless `L1LPTDataCache.cacheTotalSupply` function accepts arbitrary `gasLimit` value used by the automatic redeemer.
2. A potential for severely outdated `totalSupply` amount. Native retryable ticket can be kept alive indefinitely by calling [ArbRetryableTx.keepalive(bytes32 ticketId)](https://docs.arbitrum.io/for-devs/dev-tools-and-resources/partials/precompile-tables/_ArbRetryableTx#:~:text=keepalive(bytes32%20ticketId))) every 7 days.
3. Missing freshness check. The receiving L2 method `finalizeCacheTotalSupply` does not validate that the message was sent recently; no expiration is implemented at the application level.
### Why it's not an issue
- This hasn't been a problem so far: the `totalSupply` on L1 hasn't changed since the migration to Arbitrum (and the deployment of the contracts in question).
- Triggering the attack currently requires either burning LPT tokens on L1 or bridging a massive amount of LPT from Arbitrum back to the Ethereum Mainnet. This makes the likelihood extremely low.
- The issue is monitored offchain. If an outdated ticket is found, it can be pemissionlessly redeemed by anyone, effectively cancelling the attack even before the value gets outdated.
### Out of scope for the bug bounty
Reports targeting missing freshness check inside [L2LPTDataCache.finalizeCacheTotalSupply](https://github.com/livepeer/arbitrum-lpt-bridge/blob/fb75e274c28e5d4332fc177961904df67a38745d/contracts/L2/gateway/L2LPTDataCache.sol#L81-L92) method will be closed as known issues and are not eligible for rewards under the [Livepeer Immunefi bug bounty program](https://immunefi.com/bug-bounty/livepeer/information/), unless the report shows how the severity can be escalated beyond what is already shown above.
### References
- [L2LPTDataCache.finalizeCacheTotalSupply](https://github.com/livepeer/arbitrum-lpt-bridge/blob/fb75e274c28e5d4332fc177961904df67a38745d/contracts/L2/gateway/L2LPTDataCache.sol#L81-L92) – source code of the method with missing freshness check
- [0xd78b6bd09cd28a83cfb21afa0da95c685a6bb0b1](https://arbiscan.io/address/0xd78b6bd09cd28a83cfb21afa0da95c685a6bb0b1#code) – deployed, currently active version of the contract
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with contracts/L2/gateway/L2LPTDataCache.sol, especially finalizeCacheTotalSupply, and compare it with contracts/L1/gateway/L1LPTDataCache.sol and the linked Arbitrum retryable-ticket behavior. Search the repository for related cache, bridge, and reward tests. Done should include a decided freshness rule and validation that outdated cross-chain messages cannot affect later reward rounds.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- solidity
- Domain
- blockchain, security
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 30/100