Skip to content

fix(share): stop leaking content-derived turn ids in published snapshots#394

Merged
graydawnc merged 1 commit into
mainfrom
fix/share-snapshot-privacy
Jun 12, 2026
Merged

fix(share): stop leaking content-derived turn ids in published snapshots#394
graydawnc merged 1 commit into
mainfrom
fix/share-snapshot-privacy

Conversation

@graydawnc

Copy link
Copy Markdown
Collaborator

What

Remap every turn id to an opaque positional token (`t0`, `t1`, …) before a snapshot is uploaded, so neither `turns[].id`, `turn_order`, nor `hidden_turns` carry content-derived values. Also: external links in rendered markdown now open in a new tab with `rel="noreferrer noopener"`, and the reader's `decodeSnapshot` best-effort decodes (and warns) on an unknown `schema_version` instead of trusting it silently.

Why

Turn ids came from `ensureTurnIds`, an fnv1a32 hash of the turn body. Emitting them on the public snapshot let any reader of `/api/snapshots/` fingerprint content (reversible for known content classes) and enumerate exactly which/how many turns the author excluded — contradicting the blank-body guarantee for hidden turns. The markdown links lacked `rel`/`target`, allowing top-frame navigation and a window.opener handle.

How it connects

The reader only uses ids for ordering and hidden-lookup, never for content, so opaque positional ids are fully compatible. Adds a regression test that fails on the pre-fix code (asserts no content-hash id appears in the emitted snapshot) plus link-hardening and unknown-version tests.

Turn ids from ensureTurnIds are fnv1a32 content hashes; emitting them in
turns[].id / turn_order / hidden_turns let any reader of the public
snapshot JSON fingerprint content and enumerate which turns the author
excluded. Remap ids to opaque positional tokens before upload.

Also: external links in rendered markdown now open in a new tab with
rel="noreferrer noopener", and decodeSnapshot warns (best-effort
decode) on an unknown future schema_version instead of trusting it
silently.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@graydawnc
graydawnc added this pull request to the merge queue Jun 12, 2026
Merged via the queue into main with commit a3e9837 Jun 12, 2026
6 checks passed
@graydawnc
graydawnc deleted the fix/share-snapshot-privacy branch June 12, 2026 10:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant