Security and access
The unglamorous work, described precisely
None of this appeared anywhere on the previous version of this website, which is odd, because it is the part that separates AlumDeck from a theme with a contact form bolted to it.
- Two-factor
- App or emailed code, RFC 6238, no dependency
- Permissions
- 13 admin areas, granted one at a time
- Audit log
- 17 record types, plus sign-in events
- Admin sessions
- 60 minutes idle, 12 hours absolute
Two-factor
Written from the specification, not pulled from a package#
An admin can use an authenticator app or an emailed one-time code. The authenticator side is an RFC 6238 implementation written for this product with no third-party dependency, checked against the published test vectors, six digits on a thirty-second step, tolerating one step of clock drift. There is a QR code to scan and a typed secret for the phone that will not scan.
Turning it on is itself protected: enrolment needs an emailed code first, which opens a fifteen-minute window. Eight failed challenges lock the account for fifteen minutes and write that to the log. There is a forty-five-second cooldown on resending a code, the session identifier is regenerated the moment two-factor passes, and a half-authenticated session expires after ten minutes. If somebody genuinely loses their device, a single command from the server clears it.
Off by default, one line from compulsory. Every install ships with two-factor available but not required. There is a single configuration line that makes it compulsory for every admin account, and we would encourage you to set it. But we will not claim mandatory two-factor when a fresh install does not have it. Separately, there is no two-factor for member accounts at all.
Sessions
An admin session that ends whether you remember to or not#
Sixty minutes idle
And the panel's own background polls, which fire every thirty seconds or so, are classified as passive: they enforce the deadline but never push it back. A tab left open does not keep you signed in.
Twelve hours absolute
Counted from sign-in, whatever you are doing. There is no way to extend it short of signing in again.
No remember-me in the panel
Admin sign-in offers no remember-me box, and any remember-me session found is terminated outright with its token cycled, because it would walk straight past the rules above.
Bound to the browser, rotated on a timer
The session is tied to a hash of the browser it started in, and a mismatch ends it. The session identifier is rotated every thirty minutes. Signing in from a new address is written to the log, deliberately without locking anyone out, because phones change address legitimately all day.
Permissions
Thirteen areas, handed out one at a time#
There are two tiers and no role system to configure. A full administrator can reach everything. Everybody else holds a list of areas: registrations, members, news, galleries, events, community, association, contact, heritage, giving, surveys, communications and users. An account with no areas at all cannot sign in to the panel in the first place.
The practical version: give the person who runs the reunion the events area and nothing else. Give the door volunteer the same, and they can check tickets in and see nothing else in the building. Give the treasurer giving. None of them can open the member register.
Some things are stricter still and need a full administrator: every settings screen, the backups screen, the member import wizard and the menu builder. The import wizard re-checks on every request rather than only when the page loads.
Self-escalation is closed off, deliberately. A staff account that is not a full administrator does not see the full-administrator switch, and submitting it anyway does not persist. They also cannot grant the users area to anybody, which is the permission that would let somebody edit permissions. And nobody can delete their own account.
The audit log
Append-only, read-only, and specific about its own limits#
Creates, edits and deletes are recorded across seventeen record types, including members, registration applications, users, posts, events, association documents, gallery albums, job postings, contact messages, pages, notable alumni, memorials, committee members, timeline entries, categories, school records and deletion requests.
Alongside those sit the events that matter when something has gone wrong: sign-in, sign-out, failed sign-in with the email address masked, sessions terminated with the reason, sign-in from a new address, two-factor lockouts, two-factor turned on and off, member deactivation and anonymisation, member imports that succeeded and failed, and every change to a tracking snippet. Each row carries who, what, when and the IP address.
The table has no update timestamp and the admin screen has no edit or delete action of any kind. Rows are pruned monthly, keeping a year by default, and the floor is thirty days: it cannot be configured down to nothing.

Three things it is not. It records which fields changed, never the values, so there is no before-and-after view and nothing that could be described as a diff. It does not record the browser. And it is append-only and read-only in the admin panel, which is not the same as storage-level immutable: somebody with database access can still reach it. Gifts, campaigns, email campaigns, surveys, menus and media are not audited at all.
Two quieter defences
Exports and admin-written content#
Spreadsheet formula injection
Every CSV export escapes cells that begin with a character a spreadsheet would treat as a formula. The attack it stops is real and specific: a member sets their employer to a formula, and it runs on a committee member's laptop when they open the export.
Cross-site scripting in rich text
All admin-written rich text passes through an allowlist sanitiser when it is rendered, not when it is saved. Scripts, frames, embeds, styles and event handlers are removed with their contents, links are restricted to safe schemes and given safe attributes, and top-level headings are demoted so admin content cannot break the page structure. The intent is that even a compromised admin account cannot store something executable in a public page.
Alongside those: security headers on every response, a strict transport policy over HTTPS, rate limits declared per route rather than globally, and correct visitor addresses behind Cloudflare so those limits apply to the right person.
What we will not claim. AlumDeck has not had an independent security audit. The sanitiser described above has no automated tests over it. Both of those are true today, and you should weigh them against the fact that you can read the source and that your data is on your own server rather than in somebody else's multi-tenant database.
Questions about security and access#
Is two-factor authentication compulsory?
Not as shipped. It is available to every admin account and each person can enable it, and there is a single line in your configuration that makes it compulsory for everyone. But a fresh install writes that line as off, so if your committee needs mandatory two-factor, somebody has to turn it on deliberately.
Does the audit log show what changed?
It shows which fields changed, never the old and new values. You get a record saying the email and city fields were changed on that member, by that person, at that time, from that address. You do not get a before-and-after comparison, and no setting produces one.
Can a limited staff account promote itself?
No. For anyone who is not a full administrator the full-administrator switch is invisible and would not save even if it were submitted, and they cannot grant the users permission to anyone. Nobody can delete their own account either.
Has AlumDeck had a security audit?
Not an independent one. That is worth saying plainly rather than implying otherwise with a badge. What we can point at is the specific work described on this page, and source you can read.
What happens to a member who leaves a laptop open?
Member sessions are ordinary sessions. The hardening described here applies to the admin panel, where an idle session ends after an hour and every session ends after twelve regardless. Members do not get two-factor at all.
See the audit log and the permission screen
Both are open on the demo. Create a limited staff account and watch what disappears from the menu.