Skip to content

chat-delegate: DeleteRequest rewrites the whole key index unconditionally, and an unparseable index silently becomes empty #592

Description

@sanity

Found while reviewing #587. Delegate-WASM change — deliberately not fixed there, because re-keying the delegate to fix a latent handler bug mints another generation, which is the exact failure mode #586 is about. This should land with the next delegate bump that happens for other reasons.

1. handle_delete_request rewrites the key index unconditionally

delegates/chat-delegate/src/handlers.rs::handle_delete_request calls set_key_index even when the key was not in the index. handle_store_request and the CAS-store path both rewrite only when adding a genuinely new key. So a no-op delete still triggers a whole-index rewrite.

2. get_key_index turns an unparseable index into an empty one

from_reader(...).ok().unwrap_or_default()

An index secret that exists but fails to parse becomes an empty KeyIndex. Combined with (1), one unreadable index read during a delete writes an empty index over the real one: every room key vanishes from ListResponse, the values remain on disk but are unreachable, and there is no error. Silent, total, permanent.

The exposure is not new — handle_store_request uses the same get_key_index when adding a key — but until #587 the client had never sent a DeleteRequest at all, so the delete path has never executed in production.

Suggested fixes

  • Make the delete a no-op on the index when the key is not present, matching Store's shape.
  • Make get_key_index distinguish absent (legitimately empty) from corrupt (refuse rather than silently truncate). A corrupt index should fail the request loudly, not erase the user's keys.

Client-side mitigation already in place

#587's branch only sends the DeleteRequest when the marker is believed present, reading the delegate-seeded tri-state (so it works in the deployed app, where localStorage throws). That reduces the unconditional rewrite from once per migrating user to once per genuinely-interrupted migration. It does not address either bug above.

[AI-assisted - Claude]

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions