Summary
The durability metadata pull merges peer-asserted vector components into the local destination_run_ids table with almost no scoping, and the merged rows later gate squirrel offload (deletion). A compromised or buggy peer holding a valid token can therefore make the local node believe content is durable on a destination it cannot itself observe — and then offload deletes the local copy.
Where
sync/durability.go — pullDurability / validateComponent (checks only: destination non-empty, origin a valid node name, run > 0)
store/destination_run_ids.go — UpsertDestinationRunID (monotonic merge, no source tagging)
offload/gate.go — reads ListDestinationRunIDs with no per-source distinction
Scenario
A volume requires ["nas", "offsite"]. Only the NAS pushes to offsite, so the laptop's only evidence about offsite is the post-sync pull from the NAS. A compromised NAS returns a component {Destination: "offsite", OriginNode: <laptop>, OriginRun: >= current} for every origin. The laptop merges it; the gate's offsite vector now "covers" everything; squirrel offload deletes local bytes that exist only on the compromised NAS.
Because the merge is keyed purely by destination name and is monotonic, a peer can also inflate a component for a target the laptop verifies itself (e.g. nas) above the laptop's own verified value — corrupting directly-verified evidence.
Fix shape
Consistent with the trusted-peer design stance, contain the blast radius:
- In
pullDurability, drop any component whose destination is not a peer-only target named in this volume's offload_requires (and never accept a component for a destination the local node syncs directly — those advance only via local verified AdvanceDestinationVector).
- Record pulled evidence tagged with the asserting peer (a source column / separate table), so the gate can weigh it as a distinct, revocable class and the audit trail can answer "which evidence gated this offload" (currently pulled vs locally-verified rows are indistinguishable).
This was flagged at PR #99 review time as inherent to the trusted-peer model; the audit traced it to a concrete data-loss chain, so it warrants the scoping fix now that offload_requires exists.
Adversarial audit of offload-v1 (auditor C C-1, auditor D F7b).
Summary
The durability metadata pull merges peer-asserted vector components into the local
destination_run_idstable with almost no scoping, and the merged rows later gatesquirrel offload(deletion). A compromised or buggy peer holding a valid token can therefore make the local node believe content is durable on a destination it cannot itself observe — and then offload deletes the local copy.Where
sync/durability.go—pullDurability/validateComponent(checks only: destination non-empty, origin a valid node name, run > 0)store/destination_run_ids.go—UpsertDestinationRunID(monotonic merge, no source tagging)offload/gate.go— readsListDestinationRunIDswith no per-source distinctionScenario
A volume requires
["nas", "offsite"]. Only the NAS pushes tooffsite, so the laptop's only evidence aboutoffsiteis the post-sync pull from the NAS. A compromised NAS returns a component{Destination: "offsite", OriginNode: <laptop>, OriginRun: >= current}for every origin. The laptop merges it; the gate'soffsitevector now "covers" everything;squirrel offloaddeletes local bytes that exist only on the compromised NAS.Because the merge is keyed purely by destination name and is monotonic, a peer can also inflate a component for a target the laptop verifies itself (e.g.
nas) above the laptop's own verified value — corrupting directly-verified evidence.Fix shape
Consistent with the trusted-peer design stance, contain the blast radius:
pullDurability, drop any component whose destination is not a peer-only target named in this volume'soffload_requires(and never accept a component for a destination the local node syncs directly — those advance only via local verifiedAdvanceDestinationVector).This was flagged at PR #99 review time as inherent to the trusted-peer model; the audit traced it to a concrete data-loss chain, so it warrants the scoping fix now that
offload_requiresexists.Adversarial audit of offload-v1 (auditor C C-1, auditor D F7b).