feat(#175): opaque base64url share fragment (no raw key in URL) + Referrer-Policy no-referrer #189

Merged
Cordy merged 6 commits from fix-frag into main 2026-08-10 22:10:11 +00:00
Owner

Implements the researched, security-first recommendation for the share-link key exposure.

Research (Bitwarden Send, Mega, PrivateBin all converge): the key belongs in the URL fragment — never sent to the server, the correct zero-knowledge design — but encoded as an opaque token, never a labelled secret. PrivateBin moved off base64 padding because mail/chat clients mangle trailing =.

Change:

  • Fragment is now base64url (no padding, URL-safe) of the age identity, not the raw AGE-SECRET-KEY-1…. Same crypto, same fragment mechanism — the URL just stops exposing a scary secret string. Since the UI displays share.url, this fixes the display everywhere for free.
  • The viewer accepts both the opaque token and legacy raw-key fragments, so links minted before this keep working.
  • Referrer-Policy: no-referrer on the public /s/ surface (+ meta tag) — the one genuine leak vector the research surfaced: a fragment isn't sent to servers, but the whole URL can leak to third parties via the Referer header.

Chose base64url-of-identity over re-deriving raw key bytes deliberately: identical security, no hand-rolled bech32 in the crypto path. Three tests (round trip, legacy passthrough, garbage inert); go test share+api + build green. CHANGELOG v0.6.6. Password mode remains the two-channel option in the dialog.

Implements the researched, security-first recommendation for the share-link key exposure. **Research (Bitwarden Send, Mega, PrivateBin all converge):** the key belongs in the URL fragment — never sent to the server, the correct zero-knowledge design — but encoded as an *opaque token*, never a labelled secret. PrivateBin moved off base64 padding because mail/chat clients mangle trailing `=`. **Change:** - Fragment is now `base64url` (no padding, URL-safe) of the age identity, not the raw `AGE-SECRET-KEY-1…`. Same crypto, same fragment mechanism — the URL just stops exposing a scary secret string. Since the UI displays `share.url`, this fixes the display everywhere for free. - The viewer accepts **both** the opaque token and legacy raw-key fragments, so links minted before this keep working. - **`Referrer-Policy: no-referrer`** on the public `/s/` surface (+ meta tag) — the one genuine leak vector the research surfaced: a fragment isn't sent to servers, but the whole URL can leak to third parties via the `Referer` header. Chose base64url-of-identity over re-deriving raw key bytes deliberately: identical security, no hand-rolled bech32 in the crypto path. Three tests (round trip, legacy passthrough, garbage inert); go test share+api + build green. CHANGELOG v0.6.6. Password mode remains the two-channel option in the dialog.
Cordy merged commit bf3b3494a2 into main 2026-08-10 22:10:11 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: Cordy/Cairn#189
No description provided.