Threat model
What we store, what could leak, and what you trust us with.
Privacy that only looks right is worse than none, because people rely on it. Here is the whole picture.
Everything the server ever stores
After an organiser purges a settled event, only aggregate counts remain: how many RSVPed, came, were refunded and were forfeited.
Known leaks and how each is closed
Anyone with the invite link can read the list of ticket hashes. If each ticket appeared the moment its payment confirmed, polling the list would time every payment.
Mitigation · The public list changes only at random moments one to three hours apart, scheduled from the event's creation and never triggered by a payment, plus when RSVPs close. New tickets and returned payments appear together at those moments; the public RSVP count, seats left and the full flag follow the list; and no check-in count is public until the event settles.
One refund paying many attendees would be fetched by each of their wallets from a sync server, showing its operator a group of people who attended together.
Mitigation · Every refund is its own transaction, sent at a random time within about three hours of the event ending, and the public list shows everyone who came as "refunding" until all refunds are done, so it can't time any one of them.
Light wallets, including attendees' own and the server's, fetch transactions from a sync server, which sees the requesting IP address and which transactions it asks about.
Mitigation · The server's wallet talks to its sync server over Tor: each transaction it fetches (a random one to five minutes after first seeing it) and each one it broadcasts gets a fresh circuit, and nothing public changes in step with those requests. Your own wallet is outside cashr's control: for high-risk events, use a wallet that connects over Tor or to a server you trust, and pay from a shielded balance.
The same address at two events would link one person's attendance across both.
Mitigation · Within an event, a reused address is refused and the deposit returned. Across events the server doesn't check: refusing would tell anyone who pays into their own event with someone else's address whether that address paid for an RSVP here. Use a fresh address for each RSVP (wallets show a new one on every Receive); the RSVP page asks you to confirm it.
Loading a page reveals an IP address to the web host and the API host, and their providers may log it.
Mitigation · The API and the HTTPS proxy in front of it keep no access logs. Confirmation downloads every ticket hash, so no request points at one ticket; every visitor of an event page polls at the same jittered pace whatever their ticket's state, even while the tab is in the background; and your ticket list never asks about all your events at once. For high-risk groups, open the pages over Tor.
Memos stay in a wallet's history for good, and anyone who later sees the wallet can read them.
Mitigation · Refunds and returns carry a fixed memo that never names the event, and purging wipes everything that would name or date it, so the event id in your deposit memo leads nowhere.
A unique deposit amount could stand out.
Mitigation · Every RSVP must pay exactly the same deposit, so inside the shielded pool they all look alike. Anything else is returned. Organisers should pick a round amount.
Paying from a transparent (t-address) balance shows the payer's address and the exact deposit amount on the public chain, which can tie them to the event.
Mitigation · Event addresses are Orchard-only, refunds go to Orchard receivers with the wallet's FullPrivacy policy (since the NU6.3 upgrade that value moves in the shielded Ironwood pool), and only the Orchard part of a refund address is kept. Attendees should pay from a shielded balance.
Whoever holds the ticket QR can use it once, and your browser keeps your tickets, with each event's name and date, so they can be listed without asking the server.
Mitigation · The refund address is dropped from your browser the next time the ticket is opened or checked after your payment is in, the saved ticket image doesn't print the event's name (its code carries the event id, which the door needs), and a ticket is removed the next time it is opened or checked after its event is purged. Remove tickets for past events from your ticket list, or all of them at once.
What you are trusting
- The server's wallet holds deposits until the event is settled. A dishonest operator could keep them, so deposits should stay small (the price of a coffee).
- The organiser's links are bearer secrets. Anyone with the manage link can settle or purge the event.
- The door device sees ticket hashes, seats and the live check-in count, and keeps the hashes to work offline until the event is settled. It never sees refund addresses. Whoever holds the door link can check in any listed ticket, and a checked-in ticket is refunded: give it only to people you'd trust with the deposits.
- The organiser's dashboard is live: it shows each ticket's hash and seat as soon as its payment confirms, check-ins as they happen, and refund transaction ids. It never shows refund addresses or deposit transaction ids. Treat the manage link like the guest list it replaces.
- After a purge, the event's id still answers with its counts (RSVPs, check-ins, deposit and capacity) and nothing else; its database row keeps its storage position among other events.
- This public instance runs on a shared server. A server is only as private as its operator and its host: high-risk groups should run their own (one command, see the docs).
- cashr can't hide that an event exists, or protect against someone photographing the room.