Security
Security at Meeting Expectations
A summary of how SEATPLAN protects the meetings entrusted to it, and how to tell us about a vulnerability.
Reporting a vulnerability
Please report privately, and never include real meeting data. Write to contact@
Mail to our contact and security addresses is received by Resend, our email processor in the United States, which keeps a copy under its own retention terms, and is forwarded to the operator's own mailbox. SEATPLAN itself stores no message content. Our forwards show whether the sender's domain authenticated the message, and never pass on web pages, archives or macro-enabled documents as attachments.
Good-faith research is welcome when you test only what you are permitted to test, do not access other people's data or disrupt the service, and give us reasonable time to fix an issue before you disclose it. Machine-readable contact details are in /.well-known/security.txt.
Accounts and sessions
- Accounts are created by invitation only. There is no public sign-up and there are no default accounts.
- People sign in with a passkey, or a password and an authenticator app, or with Google or Microsoft. Passwords are hashed with Argon2id and checked against known breaches. Owners and Admins must use multi-factor authentication: signing in with Google counts as one step, and with Microsoft only as one unless Microsoft itself asked for a second factor, so they then also use their own passkey or code.
- Sessions use secure, HttpOnly, same-site cookies with idle and absolute time limits, every change is protected against cross-site request forgery, and sign-in attempts are throttled per account and per address. A browser that has signed in before is recognised, so someone who only knows your email address can't lock you out.
- An Owner can reset a person's sign-in methods with a single-use link, and the most sensitive administrative actions are reserved to Owners and enforced in the database itself.
Data in the database
- Postgres enforces access to each meeting with forced row-level security. The service connects as a role that cannot bypass those policies, and it refuses to start if it could.
- Each saved meeting has its own AES-256-GCM data key, sealed under the installation's key. Attendee emails, notes, dietary details, travel, internal notes, dial-in details and the version history are stored encrypted, as are authenticator secrets and Microsoft tokens.
- The attendee directory and meeting groups have the same forced row-level security. Each directory profile has its own data key, under a separate key-encryption subkey, and its contact details, preferences and notes are stored encrypted. Private profiles are visible only to their owner; when an Owner or Admin reads one, it is recorded, and they cannot edit it.
- Internal notes reach only people who can edit the meeting, and no copy or report ever prints them. The menu shows each role only what it may use, and the server checks every route regardless.
- An administrator's policy can keep whole sensitivity levels from ever being saved, and can require a watermark or a strong passphrase on every PDF they produce.
- Backups are verified as they are taken and encrypted, and every time an administrator opens a meeting that wasn't shared with them, it is recorded.
- A meeting that is not saved never reaches our servers: it is read, edited and printed in your browser. The server records only that a file was imported or exported, and how many meetings.
- A meeting's budget and invoices are sent only to people whose role holds the finance permission; for everyone else the server leaves them out and keeps them unchanged when they save.
- Vendors and their contacts have the same forced row-level security and a data key per vendor. Vendor email goes only to contacts stored with that vendor, never to a typed address, with per-person and daily limits.
- Day-of log entries, the notes on checklist items, budget lines and invoices, and drivers' details on transport runs are stored encrypted with the meeting.
Attendee forms
- An attendee form is the one page reachable without an account. Its link carries a random 256-bit token after the # in the address, so it never appears in a web address a server or proxy logs; the page sends it only inside its requests, and SEATPLAN stores only a keyed hash of it.
- A link works for 72 hours by default (24 hours to 7 days), is limited to one attendee of one meeting, and stops working when it expires, is revoked or replaced, or the attendee leaves the meeting.
- The form never shows stored details unless the planner required an email code: a 6-digit code, valid for 10 minutes, with the link locked after five wrong codes. Every public request is rate-limited per address, and sending the form can require a Cloudflare Turnstile check.
- Replies are encrypted under the meeting's key, change nothing until a planner reviews and applies them, and are deleted 30 days after review or after the link expires.
Network
- All traffic is encrypted: browsers reach Cloudflare over HTTPS with HSTS, and Cloudflare reaches our servers over a verified certificate. Cloudflare decrypts the traffic at its edge to deliver it, and sees visitors' IP addresses.
- Our servers accept connections from Cloudflare only.
- The service has a single outbound path, limited to our email processor for contact mail and the emails the application sends (invitations, attendee forms, vendor email and problem-report notifications), Cloudflare's bot check, Google's sign-in endpoints when Google sign-in is on, and Microsoft's sign-in and Graph endpoints when Microsoft 365 is connected. It makes no other outbound calls, and the server's firewall blocks anything else.
- In your browser, the only thing loaded from elsewhere is Cloudflare's check on the sign-in page and on the attendee form.
- Each part of the service runs in its own isolated, read-only container on a separate internal network, and only our edge proxy is reachable from the internet, through Cloudflare alone.
- Pages carry a strict Content Security Policy and refuse to be framed by other sites.
Traceability
- A hash-chained, append-only audit log records sign-ins, role and sharing changes, policy changes, exports and print runs. It never records passwords, tokens or meeting content.
- Printed copies can carry the recipient's name or a distribution code on every page, so a copy shows where it came from.
How we build it
- Every change passes secret scanning, static analysis with rules written for SEATPLAN, dependency and configuration scanning, workflow linting, end-to-end tests and a database isolation suite before it can merge.
- Dependencies are reviewed for updates every week, and fixes follow published response times by severity.
- We assess SEATPLAN against the OWASP Application Security Verification Standard 4.0.3, Level 2, and keep a STRIDE threat model with its residual risks.