Security model for published decks
A published deck is code: HTML and JavaScript anyone can write and publish. So a deck must never run on the same origin as your account. It doesn’t:
- Your account — the dashboard, your API tokens, sign-in — is on deck.kadal.cc.
- Published decks are served from decks.kadal.cc, at
decks.kadal.cc/@handle/slug/.
They are different origins, so a deck’s script cannot read your account’s cookies, call the account
API as you, or reach into the dashboard. Opening a deck’s old deck.kadal.cc/@handle/slug/ address
redirects to decks.kadal.cc, keeping the slide you linked to.
What the split buys
Section titled “What the split buys”- The session cookie is host-only (
__Host-kd_session): the browser keeps it to deck.kadal.cc and never sends it to decks.kadal.cc. A deck has no ambient account authority at all. - The two are the same site (kadal.cc), so a top-level navigation a deck triggers to the account
— a form, a
window.open— can still carry the cookie. Every state-changing account request must come from deck.kadal.cc’s own pages, as JSON; a request a deck triggers names decks.kadal.cc (or no origin) and is refused. - The dashboard refuses to be framed, and a window a deck opens onto it loses its handle.
Because a deck is on its own ordinary origin, everything a deck needs just works there: its own cookies and storage, YouTube and other embeds, fonts, Web Workers, WebAssembly, fullscreen, the clipboard, camera and screen recording in the presenter view. A deck is also embeddable in your own site — its iframe loads from decks.kadal.cc and runs normally.
Presenting: tickets, not cookies
Section titled “Presenting: tickets, not cookies”decks.kadal.cc has no account session, so the presenter proves who they are with a ticket: a signed string for one deck, valid 12 hours, kept in the page’s memory only.
- Present and Presenter view on the deck’s dashboard page mint a ticket and open the deck
with it in the address’s
#fragment, which no server orReferersees; the deck wipes it from the address bar on arrival. - A presenter passcode answers the passcode form with a ticket.
- The presenter view passes its ticket to the windows it opens (
S, the share window).
The live room takes the presenter’s role only from a ticket. No deck can borrow another deck’s presenter session, because there is no presenter cookie on the shared decks origin.
Passcode-protected decks
Section titled “Passcode-protected decks”A viewing passcode gates the deck: its HTML and all its files. The cookie that unlocks a deck is
scoped to that one deck’s path (/@handle/slug/), so it is never sent to another deck on
decks.kadal.cc. Residual risk, worth knowing: the unlock is per browser, so a deck’s script could
request a passcode deck the same browser has already unlocked, by asking for that deck’s own
paths. Keep anything truly private off a shared link.
Reporting a problem
Section titled “Reporting a problem”Found a way around any of this? Write to the address on the privacy page before telling anyone else; we’ll answer quickly.