SECURITY
Designed in from the first commit.
Security wasn't a hardening pass before launch. It's a constraint the architecture was built around — which is why the specifics below are boring, checkable facts rather than adjectives.
Who you are, and what you may do
- Passwords are hashed with argon2id. They are never stored in plain text, anywhere, at any point.
- Session data lives in HttpOnly cookies — a malicious script in the browser cannot read it.
- Authorisation always happens on the server and is always re-read from the database. What the client claims is never trusted.
- Roles and permissions are never stored inside the login token. This is a deliberate decision that avoids two well-known problems: tokens that bloat until they become slow and fragile, and stale permissions that outlive a role change. Demote someone and they are demoted now, not when their token expires.
- Two-factor authentication via standard TOTP apps and physical or biometric security keys (WebAuthn / passkeys), with recovery codes and trusted devices.
- Step-up authentication before sensitive operations. Even an active session must prove itself again before changing an email address or starting a support impersonation.
- Rate limiting on sensitive routes, with persistent blocking of abusive addresses — not just a rolling window that resets and lets them back in.
What is encrypted, and what never arrives at all
- Passwords, payment gateway secrets, SMTP configuration, and every other confidential value are encrypted with AES-256 at rest and are never returned by any endpoint.
- Every installation generates its own encryption keys on first run. Two projects on the same codebase never share a secret, so a breach in one can never reach another.
- No secrets in logs. No system log records a password, a token, or a secret value.
Card details never reach the system.
Payment happens on the gateway's own secure page. There is no code path in Quarkino where a card number could be stored, because it is never received.
Nothing reaches business logic unchecked
| Control | What it does |
|---|---|
| Schema validation | Every input is validated against a strict schema before it reaches any business logic. |
| Security headers | Standard headers, including Content-Security-Policy, on every response. |
| CORS policy | Restricted to explicitly allowed origins. |
| Upload sanitisation | User-uploaded content — SVG in particular — is sanitised before being served, so it can't carry executable code. |
| Rate limiting | Applied to sensitive routes, with persistent blocking for repeat abuse. |
GDPR, handled properly rather than performatively
- Export and erasure
- A user can retrieve everything held about them, or request erasure.
- A clear line between deletable and retainable
- A financial document is never automatically deleted, even during account erasure. In those cases the personal data is anonymised while the legally required fields of the document remain intact.
- Retention by category
- Commercial, financial, and evidentiary data — orders, invoices, change history — is never purged automatically. Only purely operational logs, like rate-limit counters, are cleaned up. That separation is enforced in code from the start, not decided later.
Retention periods for financial documents are set per deployment, against the law that applies to it. Tell us the jurisdiction and we will tell you the number we configure.
The features that could be abused, and what stops that
Support impersonation, bulk import and export, and data export all grant broad access to data. Each is built with its own restrictions.
- A dedicated permission is required — these are never bundled into a general admin role.
- Scope is limited to the data that operator is already allowed to see.
- Every use is recorded in the audit log, without exception.
- Some require fresh step-up authentication immediately before running.
On impersonation specifically: a support operator can see exactly what the customer sees — but only for a short, limited window, only after re-proving their identity, never for sensitive operations like changing a password, email, or 2FA settings, and always with an undeniable record of who acted on whose behalf.
“Who did that?” always has an answer
Every sensitive operation — a role change, an impersonation, a manual discount, a refund, an export — is recorded with the actor, the timestamp, and the precise detail of what changed. Not a summary. The specifics.
How change history worksThe attacks we test for, before a feature is called done
Many security scenarios are on the mandatory test list for every relevant feature, which means security is part of the definition of “finished” rather than a separate review afterwards.
- Cross-organisation data leakage
- Permission escalation
- Upload restriction bypass
- Formula injection in spreadsheet exports
- Abusable payment links
- One user reaching another user's records
Found something?
We'd genuinely rather hear from you than not. There's a dedicated channel and we respond to every report.
Have a security questionnaire to fill in?
Send it. We answer them properly, and we'd rather do it early than at contract stage.
- We reply within one working day
- No sales sequence, no drip campaign
- NDA before the call if you'd prefer