EIP-8205: Withdrawal credentials preregistration

Hey! MixBytes team here! We fully support the proposal.

Some context for why we care: back in February 2022 we did the first audit of Lido’s Deposit Security Module. That construction works, but it costs a guardian committee, an off-chain daemon, and deposit-root tracking logic in the contract - a lot of moving parts and a lot of trust for what is, at its core, a missing binding at the base layer. Since then every serious delegated staking product has built its own version of the same defense - bonds, guardians, or both. Each one is designed, audited, and maintained separately, and anyone new to the space is vulnerable by default until they do the same work. That is the actual cost of leaving this at the application layer, and it is not getting cheaper as the number of withdrawal credentials per protocol grows.

Preregistration replaces all of that with one check at deposit processing time, and reuses the EIP-7002/7251 request pattern rather than inventing a new one. Nothing changes for solo stakers, top-ups, or existing validators. We think this is the right shape for a fix at this layer.

Three things we would flag.

Stranded ETH: A deposit that conflicts with an active preregistration is rejected and the ETH stays in the deposit contract forever. Incorrectly signed deposits are already treated this way on the consensus layer side (via check in is_valid_deposit_signature which is invoked if validator pubkey hasn’t been seen yet), and we agree with the reasoning - refunding mismatched deposits would make front-running attempt free to retry (but operationally costly for protocol), so permanent loss is what makes the attack self-defeating. What changes is how much data a protocol has to get right: today the deposit data, under EIP-8205 the deposit data plus a preregistration signed earlier. Same class of consequence protocols already engineer around, applied to one more input - but it means preregistration generation deserves the same rigor as deposit data generation.

The guardian model stops covering the threat model: This lands on exactly the construction we audited. DSM’s detection surface is the deposit root: guardians watch for a competing deposit that would front-run Lido’s. Preregistration moves the decisive action off that surface. A Node Operator holds the validator private key, so nothing stops them from preregistering their own pubkey against their own withdrawal credentials before handing deposit data to the protocol. No deposit happens, so guardians see nothing. The protocol’s later 32 ETH deposit then mismatches and is silently rejected - stranded permanently, no recourse, no revocation.

This is griefing rather than theft - the operator burns the protocol’s ETH but cannot redirect the stake - so it is weaker than the attack preregistration closes. Adding preregistration alongside an unchanged DSM leaves a hole neither layer watches, and a guardian-model protocol that skips preregistration entirely is exposed to it with no defense at all. The research paper accompanying the EIP notes there are not many such protocols today, but they will need to pay attention and switch. The fix is what the EIP already prescribes: verify via EIP-4788 atomically with the deposit.

Two smaller integration notes: That atomic EIP-4788 check must also require the current slot to be below the proven expiry_slot, in the same transaction. An expired preregistration stays in beacon state until the epoch-boundary sweep, so it remains provable after the consensus layer has stopped enforcing it - a presence-only check passes in that window while the deposit is no longer protected. The EIP says this; we would just underline it as a MUST, since a partially-correct implementation looks identical to a correct one until someone races it.

The other is queue stuffing. The contract does not bound how many requests it accepts per block - MAX_PREREGISTRATION_REQUESTS_PER_BLOCK = 4 caps the dequeue rate, not admission - and every submission in a block pays the fee computed from the excess persisted before that block, so the fee does not rise within the block. An attacker can stuff hundreds of requests into one block at roughly gas cost, producing a FIFO backlog hundreds of blocks deep in which nobody can pay for priority. This is inherited from EIP-7002 and an accepted tradeoff, not an argument against the EIP, but a protocol that assumes its preregistration lands within a few blocks may be caught off-guard - the ~36-day window absorbs this only if the protocol is built to wait.

Overall - the vulnerability class is old and has been handled by application-layer workarounds for years because there was no alternative. Closing it at the base layer removes trust assumptions and maintenance burden from every involved protocol at once, and lowers the bar for new entrants to be safe by default.

Again, we totally support it.

5 Likes