← CrewQR

Security

How the system is built, what protects your records, and what we have not done yet. Last checked against the running servers on 20 August 2026.

Everything below was verified on the live system, not read off a diagram. Where we could not confirm something, it says so rather than sounding confident. The list of things we have not done is at the bottom, and it is not padding.

Getting your data to us

Every connection is encrypted. The servers offer TLS 1.2 and 1.3 and refuse TLS 1.0 and 1.1 outright — an old browser does not get a quietly weaker connection, it gets no connection. Certificates come from Let's Encrypt and renew automatically.

The site sends Strict-Transport-Security with a one-year lifetime covering subdomains, so once a browser has seen your company's CrewQR address it will refuse to speak to it unencrypted even if somebody hands it a plain link. Pages also send X-Frame-Options: DENY, X-Content-Type-Options: nosniff and a Referrer-Policy that keeps your company's address out of other people's logs.

Keeping companies apart

Each company gets its own database, with its own credentials, on its own address. Not a shared table with a company column in it — a separate database. The difference matters on the worst day: the usual way one customer sees another customer's data is a query that forgot to filter, and there is no filter here to forget.

The application works out which company it is serving from the address it was asked for, and if it cannot work that out it stops. It does not guess, and it does not fall back to a default.

Passwords and PINs

Passwords and crew PINs are stored as one-way hashes using bcrypt. We cannot read them. If you lose a password, nobody at CrewQR can look it up and read it back to you, because that is what one-way means — the recovery path replaces the credential rather than revealing it.

Backups

Every database is copied nightly. Copies are kept for a fortnight, and the first copy of each month is kept for four years, because wage records are expected to be retained three to four years and a backup that expires before the obligation does is not much use.

Copies are written outside every web root, owned by root and readable by nobody else, then shipped off the machine to object storage with encryption requested explicitly on every upload.

The credential that ships them can do exactly two things: list the bucket, and add to it. We tested it. It is refused when it tries to read a backup back, and refused when it tries to delete one. That asymmetry is the whole point — a server that somebody else takes control of still cannot read your history out of the backups or destroy them, because the key it holds was never able to do either.

Which raises the obvious question: if the server cannot delete a backup, what expires one? The storage does. The fortnight and the four years are rules held on the bucket itself, applied and checked with a separate administrative credential that lives on nobody's server. For a while they were not there at all — this page described a retention policy that was running on the copies on the server's own disk and on nothing else, so the off-box copies never expired. That was found and fixed rather than quietly reworded, and it is the reason this paragraph exists.

Proving the backups work

A backup nobody has restored is not yet a backup. Every Sunday morning a job takes the stored copies, restores them into a scratch database, checks that what came back contains what it should, and throws the scratch copy away. If that job fails, or simply stops running, the health monitor notices and says so.

This is not theoretical caution. An earlier version of the backup job sent error messages into the compressed stream alongside the data, which produced files that were the right size, correctly compressed, and unrestorable. Every shallow check passed. The restore is the check because it is the only one that would have caught that.

What is not encrypted, plainly

The live database sits on an ordinary filesystem on the server. We do not add a separate encryption layer underneath it, and the database does not encrypt its own tables. What protects your records there is access control — who can reach the machine, and with what credentials — not cryptography.

We would rather write that down than let "bank-level encryption" do the work of a sentence. Encryption at rest defends against somebody walking off with a disk. It does nothing about a stolen password, which is the way this actually goes wrong, and we would rather spend the effort there than on the phrase.

Who at CrewQR can reach your records

Support can open your account, and there is a button that does it. This page used to say there was not, and that was true until the day somebody rang up about Tuesday's overtime and the alternatives were asking for their password — the one thing this app tells them never to give anybody — or talking them through screenshots on the telephone. We would rather say plainly what the button does than keep a sentence we had to work around.

What it does: signs a member of staff in to your app read only, for thirty minutes, after they have typed a reason. Every write is refused — not by somebody remembering to be careful, but by a list of what a support session may run, which refuses anything not on it, so an action added next month is refused until somebody puts it there deliberately. There is no way to escalate to writing, because we have not needed one.

What you get: the whole thing lands in your own activity log, twice — when somebody asks for the link, and again when they open it — with their name and the reason they typed. Not a log we keep about ourselves. Yours, on your own screen, without asking us for it. And while a session is open, a band across the bottom of every page of your app says so and cannot be dismissed.

There is one exception, and it is worth saying rather than hiding behind the word "panel". A command-line tool can export a company's entire records — every hour, rate, punch location and photograph. It exists because suspending a company must never be the thing that takes their records away: hours are wage evidence, they are expected to be kept for years, and a billing dispute is not a reason for somebody's proof of a break to become unreachable. A suspended account cannot sign in to press the button itself, so somebody has to be able to press it for them.

Every use of it is written to the same activity log the panel writes to, with who ran it, which company, and how many bytes left the server. If we take a copy of your records, there is a line saying so, and you can ask us for it.

What we hold about you as a customer — your name, your company, your billing details — is described on the privacy page.

Any administrator can export everything their company has, at any time, without asking us. That is deliberate. Data you can only get by requesting it is data somebody can decline to give you.

Who else is involved

Amazon Web Services hosts the servers, storage and backups, and sends our email. That is the list. No analytics, no advertising, no tracking pixels, no third-party scripts inside the app. The marketing site loads a font from Google; the app does not load anything from anywhere.

What we have not done

This is a young product, and pretending otherwise would be the least trustworthy thing on the page.

Telling us about a problem

If you find a security problem, write to security@crewqr.com. It is routed, it was tested by sending to it, and a report there is pinned above ordinary support mail so it is not read as a pricing question. We will confirm we received it. We will not threaten you, and we will not ask you to keep quiet about it — if you found something real, the people using this product deserve to know it got fixed.

CrewQR · v1.14.145 · Terms · Privacy