Skip to content

Add optional length limit to ProgressiveVariableList - #86

Merged
michaelsproul merged 8 commits into
sigp:mainfrom
eserilev:progressive-list-optional-limit
Sep 28, 2026
Merged

michaelsproul merged 8 commits into
sigp:mainfrom
eserilev:progressive-list-optional-limit

Conversation

@eserilev

@eserilev eserilev commented Sep 10, 2026 •

Copy link
Copy Markdown
Member

Add an optional length limit to ProgressiveVariableList

This lets Gloas fields easily enforce their spec count limits

@codecov

codecov Bot commented Sep 10, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 87.34177% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 59.25%. Comparing base (3110fa0) to head (f865786).

Files with missing lines Patch % Lines
src/progressive_variable_list.rs 86.66% 8 Missing ⚠️
src/serde_utils/prog_list_of_hex_fixed_vec.rs 66.66% 1 Missing ⚠️
src/serde_utils/prog_list_of_hex_prog_var_list.rs 91.66% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #86      +/-   ##
==========================================
+ Coverage   53.37%   59.25%   +5.88%     
==========================================
  Files          18       18              
  Lines         622      675      +53     
==========================================
+ Hits          332      400      +68     
+ Misses        290      275      -15     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@eserilev
eserilev changed the base branch from main to progressive September 10, 2026 23:47
@eserilev
eserilev force-pushed the progressive-list-optional-limit branch 2 times, most recently from 665b0b8 to 9292e9f Compare September 10, 2026 23:55
@michaelsproul

Copy link
Copy Markdown
Member

huh, I thought progressive lists didn't have any limits?

where are the limits defined?

@eserilev

eserilev commented Sep 11, 2026 •

Copy link
Copy Markdown
Member Author

they dont have limits. This adds a guard to decoding so that we dont end up decoding a massive object and OOM ourselves

for example MAX_ATTESTATIONS_ELECTRA in blocks, we should fail early decoding a block whose list of attestations exceeds the max

we dont have to necessarily include the guard here, but I thought it might be the cleanest option

this issue was flagged by one of the security researchers here:
https://discord.com/channels/595666850260713488/892088344438255616/1547691356615479377

@michaelsproul

Copy link
Copy Markdown
Member

my understanding was that we'd try to enforce bounds one level up at the network later, e.g. don't decode a block larger than X kB

I think we have those limits in LH but they are set absurdly high at the moment due to the payload size. We could probably greatly reduce the cap for blocks

@michaelsproul

Copy link
Copy Markdown
Member

I'm coming around to this change, I think we should try to put the length limit checks as "low" and early as possible.

I tried putting them into the decode for BeaconBlock, but even that feels a bit too high because we sometimes construct BeaconBlocks without SSZ decoding (e.g. during proposal, or receiving a JSON BeaconBlock over HTTP).

@michaelsproul michaelsproul left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Impl looks solid, I think this is the way to go.

I'll try cooking up a Lighthouse branch to use these changes.

Comment thread src/progressive_variable_list.rs Outdated
@michaelsproul
michaelsproul force-pushed the progressive-list-optional-limit branch from 9292e9f to 742c4c6 Compare September 22, 2026 01:54
@michaelsproul
michaelsproul changed the base branch from progressive to main September 22, 2026 01:55
@michaelsproul

Copy link
Copy Markdown
Member

rebased on main

@michaelsproul

Copy link
Copy Markdown
Member

@eserilev Why did you revert the early failures in Deserialize/ContextDeserialize? (this commit: 31f9025)

They seemed OK to me, did you just want to save on complexity?

@michaelsproul

Copy link
Copy Markdown
Member

I checked all your commits and they look good, so I'm happy to merge this.

@eserilev

Copy link
Copy Markdown
Member Author

yeah it just seemed overly complex, my b for the last minute changes!

@michaelsproul
michaelsproul merged commit 8955d22 into sigp:main Sep 28, 2026
9 checks passed

/// Returns the optional length limit.
///
/// `None` means no limit (`N = U0`). `Some(n)` rejects any input with more than `n` elements.

@macladson macladson Sep 28, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit late here but just noting that this could lead to an edge case since we cannot define anything to have a limit of 0. It would instead have no limit. This is most relevant for Deposit which is spec'd with a limit of 0: https://github.com/ethereum/consensus-specs/blob/638af25cd7adea0314c71a6052262c1a5ad6f368/specs/gloas/beacon-chain.md?plain=1#L305-L312

This likely isn't an issue for Lighthouse currently since we reject non-empty deposits either way:

https://github.com/sigp/lighthouse/blob/73e4dc120dfb49fbc5123d4fad42d935a94f368f/beacon_node/beacon_chain/src/block_verification.rs#L910

Theoretically if we could de-couple U0 from None we could set MaxDeposits to U0 and reject non-empty Deposits at decode time rather than during verification.

Also, as a side note, for VariableList, U0 actually does mean "limit of 0" so this is inconsistent API-wise.

mergify Bot pushed a commit to sigp/lighthouse that referenced this pull request Sep 29, 2026
## Issue Addressed

Trying to solve ProgressiveList DoS vectors.

## Proposed Changes

Go back to type-level limits like before, using:

- sigp/ssz_types#86

## Additional Info

Several imperfections we still need to solve:

- [ ] There's no bound on transactions and we probably need a spec change to safely add one (related: ethereum/consensus-specs#5642 (comment))
- [x] The upstream `ssz_types` initially only enforced the limits in some places. I've now changed it to enforce them everywhere to avoid oversized lists slipping through. For example `ProgressiveVariableList::try_from_iter` didn't enforce the limit but was reachable from indexed attestation JSON decoding (via `quoted_u64_var_list`). See: sigp/ssz_types#86 (comment).


Co-authored-by: Pawan Dhananjay <pawandhananjay@gmail.com>
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.

3 participants