Skip to content

docs: add tokenomics vulnerabilities 39 and 40 - #351

Merged
DavidMinarsch merged 1 commit into
mainfrom
docs/vuln-list-additions-2026-08-31
Aug 31, 2026
Merged

docs: add tokenomics vulnerabilities 39 and 40#351
DavidMinarsch merged 1 commit into
mainfrom
docs/vuln-list-additions-2026-08-31

Conversation

@DavidMinarsch

Copy link
Copy Markdown
Contributor

Two new entries, from internal review.

39 — A retired L2 target dispenser cannot forward or release a late arrival

DefaultTargetDispenserL2.migrate() sweeps the balance to the new dispenser and then closes the old one permanently:

// Zero the owner
owner = address(0);
...
// _locked is now set to 2 for good

Both statements are terminal, and the closing comment records the intent. With owner zeroed every owner-gated path is unreachable; with _locked left at 2 every guarded path is too.

A staking claim's token leg and message leg settle independently. A token leg dispatched before migration can land afterwards on an address with no code path able to move it — no forwarding function, no rescue. The amount is unrecoverable, not merely stuck.

migrate() does require a pause first, which is the intended settle-then-migrate procedure — but a pause stops new dispatches, not a transfer already in flight across the bridge. Nobody can cause this deliberately; the trigger is the migration's own timing, so it is recorded as an operational property rather than an attack.

Mitigation: keep a forwarding path on the retired dispenser — leave owner set to the new dispenser, or add a rescue(address token) callable by it.

40 — L1 claim state advances before an Arbitrum retryable is known redeemable

if (params.gasPriceBid < 2 || params.maxSubmissionCostMessage == 0) {
    revert ZeroValue();
}

A bid of 2 passes. A reserve-covered claim then advances L1 bookkeeping — including consuming the withheld amount — and enqueues the retryable at that boundary value. If the bid is not executable, the message can expire while the L1 side already treats the claim as settled.

The bid is the claimant's own input, and a low one mainly harms their own message. What is not theirs to control is the ordering: state advances before delivery is known to be executable, which is a property of the state machine rather than of any caller's input.

Raising the constant is not a durable answer — any fixed floor can be under-priced later — so the mitigation is on advancing state, not on the bid.

Table of contents verified against headings.

39. DefaultTargetDispenserL2.migrate() sweeps the balance to the new dispenser and
then closes the old one permanently - owner is zeroed and _locked is left at 2,
which the contract's own closing comment records as deliberate. Both are terminal:
owner-gated paths and reentrancy-guarded paths alike become unreachable. A staking
claim's token leg and message leg settle independently, so a token leg dispatched
before migration can land afterwards on an address with no code path able to move
it, with no forwarding function and no rescue. The amount is unrecoverable rather
than stuck. migrate() does require a pause first, which is the intended
settle-then-migrate procedure, but pausing stops new dispatches rather than a
transfer already in flight. Nobody can cause it deliberately - the trigger is the
migration's own timing - so it is recorded as an operational property.

40. ArbitrumDepositProcessorL1 enforces a fee floor of exactly two wei, so a bid of
2 passes. A reserve-covered claim advances L1 bookkeeping, including consuming the
withheld amount, and enqueues the retryable at that boundary value; if the bid is
not executable the message can expire while the L1 side already treats the claim as
settled. The bid is the claimant's own input and a low bid mainly harms their own
message. What is not theirs to control is the ordering - state advances before
delivery is known executable - which is a property of the state machine rather than
of any caller's input. Raising the constant is not a durable answer, since any fixed
floor can be under-priced later, so the mitigation is on advancing state.
@DavidMinarsch
DavidMinarsch merged commit 6248465 into main Aug 31, 2026
3 checks passed
@DavidMinarsch
DavidMinarsch deleted the docs/vuln-list-additions-2026-08-31 branch August 31, 2026 09:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant