Skip to content

CRITICAL: fail-OPEN seal — E2e KB ships PLAINTEXT to the key-blind daemon when content key absent / seal fails #168

Description

@cuttlefisch

Found + VERIFIED in the impl-pass security review over merged 3b (#160). CRITICAL.

Bug

crates/mae/src/collab_bridge.rs::build_kb_node_update_request chooses seal-vs-plaintext purely on
content_key.is_some() (the match (content_key, signing_identity)), with no knowledge that the KB is E2e:

  • _ => arm (no key): ships the plaintext update as the wire payload.
  • Err(_) => arm (seal failed): also ships plaintext — comment "fail safe: keep the plaintext payload rather
    than dropping the edit" — that is the bug for an E2e KB.

content_keys (network task, init empty at ~:2849) is repopulated only in-session: enable (:3674), rotation
(:3476), share/join responses (:4477/:4622). There is no startup reload into the seal path (the
content_key_store::load at :3642 is only inside the enable handler). So after a restart/reconnect, editing an
already-E2e node before a share/join response repopulates the map → content_key=Noneplaintext written to
the key-blind daemon
, which stores + relays it. Silent confidentiality breach — exactly what ADR-037 prevents.

Fix (fail CLOSED)

Gate the seal decision on the KB's authoritative (signed) encryption mode, not map presence. When
derive_encryption(...)==E2e (or a known per-KB e2e flag) and the key is missing OR seal_op errors: do not
send
— requeue + surface an error/notification. Thread an e2e: bool into build_kb_node_update_request so the
no-key and Err arms return no payload when e2e. Also repopulate content_keys at task startup from
content_key_store for owned/joined E2e KBs.

Test gap

collab_bridge_tests.rs:2768,2788 pass content_key:None and assert the plaintext path — framed as legacy/
unencrypted. No test asserts "E2e KB + missing key ⇒ MUST NOT emit plaintext."

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:collabCollaborative editing / sync / CRDTsecuritySecurity / auth / access control

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions