Summary
The peer-sync receiver accepts a transferred file's content origin verbatim from the wire, but validateEntryOrigin does not reject an origin that names the receiver's own node with an arbitrary run id. One malicious sync permanently poisons the self component of the receiver's durability vector, after which the receiver's own never-backed-up files pass the offload gate.
Where
agent/sync.go — validateEntryOrigin (requires only valid node name + OriginRun > 0; no self-name rejection, no run upper bound)
agent/sync.go — originResolver.provenance; store/nodes.go — GetOrCreateOriginNode (resolves by name, matches the self row)
store/destination_run_ids.go — presentOriginMaxima uses the forged origin run verbatim (the NULL-origin remap does not fire for a non-NULL origin)
Scenario
A malicious initiator transfers a single new (unique-blake3) file declaring origin_node = "<receiver self name>", origin_run = 2^62. At /close the receiver writes a contents row with origin (self.ID, 2^62). The next time the receiver syncs the volume to any required target T, AdvanceDestinationVector takes MAX(origin_run) for the self component = 2^62 and upserts T[self] = 2^62. Monotonic, so permanent.
From then on every future locally-introduced file (NULL origin → mapped to (self.ID, intro_run), a far smaller real run id) satisfies 2^62 >= intro_run and passes the offload gate for T though it was never synced to T. A single malicious sync permanently disarms the offload safety check for the victim's own content.
The analogous GetOrCreatePeerNode already refuses a peer claiming the self-name; the origin path is the asymmetric hole.
Fix shape
In validateEntryOrigin: reject an origin_node equal to the receiver's self-node name (a peer is never authoritative about the receiver's own introductions — let it re-introduce locally with a NULL origin), and bound origin_run so a peer cannot assert a self-run above the receiver's own latest allocated run id. Both are cheap boundary-local checks.
Adversarial audit of offload-v1 (auditor C C-2).
Summary
The peer-sync receiver accepts a transferred file's content origin verbatim from the wire, but
validateEntryOrigindoes not reject an origin that names the receiver's own node with an arbitrary run id. One malicious sync permanently poisons the self component of the receiver's durability vector, after which the receiver's own never-backed-up files pass the offload gate.Where
agent/sync.go—validateEntryOrigin(requires only valid node name +OriginRun > 0; no self-name rejection, no run upper bound)agent/sync.go—originResolver.provenance;store/nodes.go—GetOrCreateOriginNode(resolves by name, matches the self row)store/destination_run_ids.go—presentOriginMaximauses the forged origin run verbatim (the NULL-origin remap does not fire for a non-NULL origin)Scenario
A malicious initiator transfers a single new (unique-blake3) file declaring
origin_node = "<receiver self name>",origin_run = 2^62. At/closethe receiver writes acontentsrow with origin(self.ID, 2^62). The next time the receiver syncs the volume to any required targetT,AdvanceDestinationVectortakesMAX(origin_run)for the self component =2^62and upsertsT[self] = 2^62. Monotonic, so permanent.From then on every future locally-introduced file (NULL origin → mapped to
(self.ID, intro_run), a far smaller real run id) satisfies2^62 >= intro_runand passes the offload gate forTthough it was never synced toT. A single malicious sync permanently disarms the offload safety check for the victim's own content.The analogous
GetOrCreatePeerNodealready refuses a peer claiming the self-name; the origin path is the asymmetric hole.Fix shape
In
validateEntryOrigin: reject anorigin_nodeequal to the receiver's self-node name (a peer is never authoritative about the receiver's own introductions — let it re-introduce locally with a NULL origin), and boundorigin_runso a peer cannot assert a self-run above the receiver's own latest allocated run id. Both are cheap boundary-local checks.Adversarial audit of offload-v1 (auditor C C-2).