Files
pulsar/pkg
zeekay 160df36c07 fix(pulsar): hard-cap PartyID before signer-bitmap allocation (DoS)
Item7(a) library-side defense-in-depth, on SHIPPED pulsar v1.9.0 (the tag
cloud's consensus v1.35.30 pins). Non-breaking: CanonicalSignerSet's
2-arg signature is UNCHANGED so the existing consensus consumer compiles
and runs unmodified.

CanonicalSignerSet sized the signer bitmap at make([]byte, maxID/8+1)
with maxID taken straight from an attacker-controlled uint32 Partial.
PartyID and no upper bound — a single Partial naming PartyID near
math.MaxUint32 drives a ~512MiB allocation (memory-exhaustion DoS).

Added MaxCanonicalPartyID = 1<<20 (bitmap <= 128 KiB) and a typed
ErrPartyIDOutOfRange; CanonicalSignerSet now rejects any partial in
`valid` whose PartyID >= the cap BEFORE the sort or the allocation. The
whole slice is checked, not just the chosen subset, so a hostile PartyID
cannot hide behind the threshold cut. The cap sits far above any real
validator set (Lux runs hundreds to low thousands) so legitimate inputs
are never rejected.

This is orthogonal to — not a replacement for — the consumer's own
exact-ValidatorSetSize bound (consensus PulsarRoundSigner.Finalize, its
companion commit): the library needs no external context and stays
signature-stable, so this hardening protects any future caller lacking
that upstream guard.

New test: TestCanonicalSignerSet_RejectsOversizedPartyID (MaxUint32,
excluded-from-chosen, at-cap boundary, and the just-below-cap happy path
with a bounded bitmap). No go.mod/go.sum change.
2026-07-08 07:34:25 -07:00
..