D2Q
Writeup · · 3 min read

The asymmetry that was a design: an honest negative on SSV Network

SSV tracks validator weight with a deviation term that is added in some paths and subtracted in others. It looks like a residual you could farm into an inflated earning rate. We wrote the probes to farm it. It nets to exactly zero.

By doom2quake, a human builder collective.

Two tall columns of light netting to a flat zero line with validator nodes in equilibrium, on a dark zinc field

Most of the serious work in a security review does not end in a submission. It ends in a passing test that proves the attack does not fire, and a short note on why. Those notes are the product, not the filler between findings. A surface you have genuinely tried to break and could not is worth more than one nobody looked at. This is one of those.

The thesis

SSV Network tracks validator weight in units it calls vUnits. The shape that draws the eye is a deviation term: a cluster’s stored vUnits minus its validator count times a base unit. That deviation is added to the DAO and operator totals in some code paths and subtracted in others, and the baseline it is measured against is recomputed at different moments in different paths.

That is a classic seam. If the validator count changes between an add and a later remove, the add and the remove would be measured against two different baselines, and a residual should survive in the DAO and operator totals. That residual would quietly inflate the network earning rate that pays cSSV stakers, or an operator’s earning multiplier. A permissionless way to leave a non-zero residual behind is a real, ongoing drain. Worth chasing to a proof.

The refutation

It is a deliberate two-part model, not an accident. The baseline is always carried in one field, the validator count times the base, and the deviation is carried separately. The removal path keeps the deviation in lockstep with the count: every removed validator subtracts exactly one base unit from the stored vUnits, and when the count reaches zero the code force-cleans whatever deviation is left. Liquidation deliberately does not reset the deviation, so that reactivation re-adds exactly what liquidation removed. Every add and remove therefore measures against a baseline that has been kept consistent with the stored value.

We did not settle this by reading. We ran three adversarial probe scenarios against a local deployment:

  • Register two validators, liquidate, remove one while liquidated, reactivate, then tear the last one down. Final DAO and operator totals both land at zero.
  • Register across four operators, remove one operator so its per-operator total is deleted while the DAO total remains, then liquidate. The DAO total goes to zero exactly, and the guard that skips a removed operator in the per-operator loop fires correctly.
  • Two clusters sharing all four operators, one spiking its balance to auto-liquidate in a single transaction. The full delta and the liquidation subtraction net to the correct per-operator value, with no leakage into the other cluster and no underflow.

All three net to zero residual. The one asymmetry we did surface, a single remaining validator understating its own weight after a partial removal, is protocol-favouring: it lowers earnings, it does not inflate them. The team had already found and fixed the obvious version of this class and shipped a regression suite for it.

The lesson

An accounting model that reads as asymmetric on a first pass is often a baseline-plus-deviation split that stays balanced by construction. The way you settle it is to force the validator count to change across the add and the remove, in the exact interleavings an attacker controls, and check that the residual is exactly zero. Not to argue about which path uses which baseline.

We filed nothing here, and that is the result: a real earning-rate surface, attacked in the sequences that would break it, that held. We keep the probes and the reason.

← All posts Browse the hackathon knowledge graph →