Skip to content

CRITICAL: epoch fence bypassed by DELETE-only ops (update_new_op_authors misses delete-set authors) #167

Description

@cuttlefisch

Found + VERIFIED in the impl-pass security review over the merged #163 fence. CRITICAL.

Bug

shared/sync/src/kb.rs::update_new_op_authors attributes new-op authors by diffing yrs state vectors
(before/after apply) ∪ the update's own SV. In YATA a deletion is a tombstone in the delete-set, not a
clock-advancing struct
— so a pure-delete update advances no client's clock and contributes nothing to
either signal. update_new_op_authors returns [], enforce_epoch_fence finds no stale author → Ok.

Verified

A probe (stale client deletes a node body via set_body("")) returns authors = [] for both an existing-lineage
client and a fresh client:

PROBE pure-delete authors = []
PROBE client-999 delete authors = []

Attacker path

A demoted-not-removed (or viewer-era) client at a stale epoch authors a DELETE of base content. kb_access(Edit)
passes (they're a current editor), enforce_epoch_fence passes (delete → no authors) on both the hub
kb/node_update and the mesh dialer paths (both consume update_new_op_authors). The censoring deletion lands +
broadcasts. (A removed member is still caught by admit/NotAMember on the signed path; this is the
demoted/unsigned-hub gap.)

Fix

In update_new_op_authors, also attribute delete-set authors: decode yrs::Update::decode_v1(update), iterate
its delete_set per-client ranges, and union every client id whose deletions aren't already covered by
base_state's delete-set. Add regression tests: a pure remove_range/remove_tag/set_body("") under a stale
client id is reported, and an end-to-end enforce_epoch_fence test that a stale-epoch delete is REJECTED.

Test gap (principle #14)

Every B-19/B-20 fence test uses set_title/set_body with non-empty text — remove_range THEN insert, and the
insert masks the gap. None exercises a delete-dominant op. The chosen inputs all happen to insert (the "unicorn
value" failure mode).

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:collabCollaborative editing / sync / CRDTarea:daemonmae-daemon (persistence, collab hub)securitySecurity / auth / access control

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions