Security
Last updated 9 September 2026
Crewmark holds employment records, hours and pay rates. This page describes what actually protects them, specifically enough that you could check.
Getting in
- Two-factor is compulsory. Not a setting somebody can leave off. A password alone reaches one screen: the one asking for your authenticator code.
- Passwords are hashed with Argon2id at the OWASP baseline — memory-hard, so a stolen hash costs an attacker real memory per guess rather than cheap parallel arithmetic. Plain-text passwords are never stored or logged.
- One-time codes work once. A code stays arithmetically valid for thirty seconds, which is long enough to be read over a shoulder, so a spent code is refused for the rest of its window.
- Second-factor secrets are encrypted at rest with AES-256-GCM, under a key held separately from the database. A stolen database does not yield anybody’s authenticator.
- Sign-in failures are indistinguishable. A wrong password, an unknown address and a disabled account produce the same message in the same time, so the login form cannot be used to enumerate who works here.
- Attempts are rate-limited per account and per address, counted atomically so a burst of simultaneous guesses is counted in full.
Staying in
- Sessions are records, not self-contained tokens. Disabling an account or changing a role takes effect on the next request rather than whenever a token would have expired.
- The cookie holds only randomness. The database stores its hash, so a leaked backup does not hand over live sessions. It is
HttpOnly,Secure,SameSite=Lax. - The session identifier changes when the second factor is satisfied, so a cookie planted before sign-in is not a signed-in one afterwards.
- Changing your password ends every other session.
Who can reach what
- Every page and every action checks permission on our servers, each time. A hidden button is not access control, and nothing here relies on one.
- Access follows the organisation chart. A manager reaches the people beneath them and no one sideways or above. Moving somebody moves their access with them.
- Money is a separate permission from people. A manager can run their team without seeing what any of them cost.
- Nobody approves their own work. Enforced in the rules and again in the queries, including for accounts that may approve everybody else.
- Exports obey the same limits as the screen. A download is built by the same code as the page; asking for a colleague’s record in the URL returns an empty file, not the colleague.
The record
- The audit trail cannot be rewritten. The database refuses to update or delete an audit entry — not by policy, by constraint. It survives being restored from backup.
- Deleting a user is refused while they appear in the audit trail. Accounts are deactivated instead, so nobody can remove themselves from the record.
- Report downloads are recorded with their row counts, which is what later distinguishes a spot check from an extraction.
The application itself
- HTTPS everywhere, with HSTS. A strict Content-Security-Policy with a fresh nonce per request; no third-party scripts, no analytics, no trackers.
- Every input is validated against a schema on the server, and identifiers arriving from a browser are never trusted.
- Database queries are parameterised throughout — there is no string concatenation into SQL anywhere in the codebase.
- Exported spreadsheets are neutralised against formula injection, so a name or a note cannot execute when a colleague opens the file.
- The application container runs unprivileged, and the database publishes no network port at all.
Data and backups
- Hosted in Switzerland, on Infomaniak.
- Backups run nightly, and each is verified before it is kept. An archive that cannot be read is failed loudly rather than filed away looking like a backup.
- Restores are tested, not assumed. A backup is restored into a scratch database and checked.
- Money is stored in decimal arithmetic, never floating point.
What Crewmark deliberately does not do
No screenshots. No keystroke or mouse monitoring. No idle detection. No reading of files, email or source control. Hours are entered by hand by the person who worked them. This is a design decision, not a gap.
Reporting a problem
If you find a vulnerability, write to no-reply@mehro.ch — it is monitored despite the name, and reaches a person. Tell us what you found and how to reproduce it. Please do not access anybody else’s data to demonstrate a point — a description is enough, and we would rather fix it than have it proven.
We will acknowledge within two working days and tell you what we intend to do. We will not pursue anybody who reports in good faith and gives us a reasonable chance to fix it first.
See also the privacy policy.