Task
The adaptive derivation window is steerable by a peer. Bound it against peer-supplied input, or make
the window's growth depend on something the peer cannot choose.
Mechanism
occupied_puzzle_hashes() reads coins, which sync::apply_coin_states fills from unverified peer
frames, filtered only by subscription membership — and the subscribed set is the window, which the
node hands the peer. So the peer learns exactly which hashes will be accepted, and coins it sends widen
the set it is then allowed to send more into.
Measured shape: a Corroborated peer can ratchet to MAX_DERIVATION_COUNT over roughly 98 unlocks, at
~12.5s per unlock, producing ~50k-hash subscription frames.
Severity, stated honestly
LOW-MEDIUM, defense-in-depth. No money is at risk and the growth is bounded — MAX_DERIVATION_COUNT
clamps it, so this is resource inflation rather than a custody defect. Filed because the feedback loop
(peer input widens the set that admits peer input) is the property worth removing, not because anything is
currently broken.
Found during the pre-merge security audit of dig-node PR #295, which PASSED — this was explicitly
non-gating.
Shape questions
- What should growth actually key on? Occupancy is the natural signal and it is exactly the
peer-supplied one. A window driven by confirmed-on-chain coins rather than by frames a peer asserts
would break the loop, at the cost of lag.
- Is a 50k-hash subscription frame acceptable on its own terms? Independently of the ratchet, that is
a large frame to send and to be asked to process.
- NC-12 binds: every dialled peer is untrusted, and
Corroborated is a state a peer reaches, not a
guarantee about it.
Related findings from the same audit, worth folding in or splitting
release_spend has no production caller — dead code on a custody-adjacent path. Wire it or delete
it; leaving it is worse than either.
MAX_DERIVATION_COUNT's comment names a hand-edited-manifest channel that does not exist
(derivation_count is a compile-time constant). The clamp is correct; its stated rationale is not, and a
false rationale is what justifies leaving a real bound unexamined.
- Reservation is gated on an untrusted
accepted — fail-open if a source denies relaying what it
relayed, fail-closed for 10 min if it over-claims. Follow-up: treat post-transmit transport failure as
possibly-in-flight.
- Resident secret-key count rises ~20x by default —
chia-bls 0.22 SecretKey has no Drop/zeroize.
Upstream, not fixable here; recorded so it is not rediscovered as a local defect.
Parent
https://github.com/DIG-Network/dig_ecosystem/issues/2760
Task
The adaptive derivation window is steerable by a peer. Bound it against peer-supplied input, or make
the window's growth depend on something the peer cannot choose.
Mechanism
occupied_puzzle_hashes()readscoins, whichsync::apply_coin_statesfills from unverified peerframes, filtered only by subscription membership — and the subscribed set is the window, which the
node hands the peer. So the peer learns exactly which hashes will be accepted, and coins it sends widen
the set it is then allowed to send more into.
Measured shape: a
Corroboratedpeer can ratchet toMAX_DERIVATION_COUNTover roughly 98 unlocks, at~12.5s per unlock, producing ~50k-hash subscription frames.
Severity, stated honestly
LOW-MEDIUM, defense-in-depth. No money is at risk and the growth is bounded —
MAX_DERIVATION_COUNTclamps it, so this is resource inflation rather than a custody defect. Filed because the feedback loop
(peer input widens the set that admits peer input) is the property worth removing, not because anything is
currently broken.
Found during the pre-merge security audit of dig-node PR #295, which PASSED — this was explicitly
non-gating.
Shape questions
peer-supplied one. A window driven by confirmed-on-chain coins rather than by frames a peer asserts
would break the loop, at the cost of lag.
a large frame to send and to be asked to process.
Corroboratedis a state a peer reaches, not aguarantee about it.
Related findings from the same audit, worth folding in or splitting
release_spendhas no production caller — dead code on a custody-adjacent path. Wire it or deleteit; leaving it is worse than either.
MAX_DERIVATION_COUNT's comment names a hand-edited-manifest channel that does not exist(
derivation_countis a compile-time constant). The clamp is correct; its stated rationale is not, and afalse rationale is what justifies leaving a real bound unexamined.
accepted— fail-open if a source denies relaying what itrelayed, fail-closed for 10 min if it over-claims. Follow-up: treat post-transmit transport failure as
possibly-in-flight.
chia-bls0.22SecretKeyhas noDrop/zeroize.Upstream, not fixable here; recorded so it is not rediscovered as a local defect.
Parent
https://github.com/DIG-Network/dig_ecosystem/issues/2760