Skip to content

[critical] Peer can self-attribute content origin, permanently poisoning the durability vector #105

Description

@mbertschler

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.govalidateEntryOrigin (requires only valid node name + OriginRun > 0; no self-name rejection, no run upper bound)
  • agent/sync.gooriginResolver.provenance; store/nodes.goGetOrCreateOriginNode (resolves by name, matches the self row)
  • store/destination_run_ids.gopresentOriginMaxima 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).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingdata-lossCould cause silent data losssecuritySecurity / data-integrity finding

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions