ContactStart a campaign
Start a campaign
Security

Privacy at the core.

Your campaign sits behind a link no one can guess and a PIN only your team receives. It is walled off from every other client’s. And every rule is checked twice, in the application and in the database.

The short version

Four things to know.

Only your team can open it.

Each tracker has its own secret link, and a PIN that goes only to the people named on your account.

Your campaign stays yours.

Every request is tied to exactly one client, and only reviewed records are ever sent to your browser.

The database says no, too.

Every access rule is checked in the application and again in the database itself.

Checked on every change.

Each protection has an automated test, so a fix can’t quietly come undone.

Access

A link no one can guess, and a PIN only your team receives.

PIN as a second factor

A 4-digit PIN, delivered separately by email, gates the dashboard. PINs are never stored: they are hashed with scrypt and a per-PIN random salt, and compared in constant time to resist timing attacks.

Even someone holding the link still needs the PIN, and we never keep the PIN itself.

Signed sessions

Unlocking issues an HMAC-SHA256 signed session cookie (httpOnly, Secure, SameSite=Lax), bound to that client and that PIN version, carrying its own expiry.

A session can’t be forged, moved to another client or extended by hand.

Instant revocation

Changing a PIN changes the version every session is signed against.

Every browser that used the old PIN is signed out at once, with no session list to clear.

Race-proof lockout

5 wrong attempts lock the dashboard for 15 minutes. Each attempt is reserved atomically in a single database operation before the PIN is checked.

Concurrent or parallel guessing can’t get past the limit.

Data protection

Your campaign is walled off from every other client’s.

Tenant isolation

Every server request is resolved from the link to exactly one client, and every query is scoped to that client.

No request can reach another client’s campaign.

Server-side rendering with an allowlist

The tracker is built on the server. Every record passes through an explicit allowlist before anything reaches the browser, so only fields approved for display are ever sent. Nothing is merely hidden in the interface.

Less travels over the network, so less could ever be exposed.

Photo provenance

Only proofs that were reviewed and sent appear. If an update is withdrawn or corrected, its photos drop out of the dashboard, the city PDF, the photo ZIP and the CSV automatically.

Whatever you see, download or forward is the reviewed record.

Database

The database enforces the rules itself.

Row-level security, deny by default

Every table runs under Postgres row-level security. The public (anonymous) role can read or write nothing. Signed-in access requires an active team membership, checked in the database itself.

If a request isn’t explicitly allowed, the database refuses it.

Least privilege by role

Owner, staff and field-operations roles are enforced at the database layer, not only in the interface. Sensitive columns (payout bank details, PIN data, client-facing wording) are guarded by database triggers. Bank changes automatically clear KYC verification.

Even a valid team session can’t change what its role doesn’t allow.

Privileged access stays on the server

The elevated database credential exists only on the server and is never shipped to a browser. Automated checks fail the build if it ever could be.

The master key never leaves our servers.

Documents and files

Files stay private, and every link to them expires in a minute.

Private object storage

KYC and company documents sit in private buckets with no public access. Every download is a signed URL that expires in 60 seconds.

A forwarded or leaked file link stops working within a minute.

Strict upload control

Each upload gets a single-use, pre-authorised object key. The server verifies the exact key, size and file type before recording it, rejects any key that could be reinterpreted (encoded traversal and similar), and caps how many uploads a link can request.

Only the file we expected, where we expected it, gets in.

Browser hardening

Your browser is told exactly what the page may and may not do.

Strict security headers

On every response: Content-Security-Policy; HSTS for one year including subdomains; frame embedding denied (anti-clickjacking); MIME sniffing disabled; no referrer leakage; a locked-down Permissions-Policy.

No clickjacking, no fallback to plain HTTP, and nothing passed on to other sites.

Injection-resistant rendering

All interface text is escaped by default. Raw HTML rendering is banned in the codebase and enforced by automated tests. Map labels and photo links are escaped and validated, and external file links open only over https to approved hosts.

Text someone types can’t turn into code on your screen.

Assurance

Kept secure as it changes.

Defence in depth

Every boundary is enforced twice: once in the application, once in the database.

One mistake on its own isn’t enough to expose anything.

Security regression tests

Each protection has an automated test that runs on every change.

A fix can’t quietly come undone.

Systematic security review

The whole system was audited surface by surface: every entry point, trust boundary and attack class mapped, every candidate issue independently verified, and every confirmed finding fixed.

Every way in was examined, and every gap found was closed.

For your IT team

Questions about how it’s built?

Your IT or procurement team can write to us directly. We’ll answer in plain terms, or in as much technical depth as they need.