Trust

Security and Architecture

Written for the person who has to approve this, not for the person buying it. It includes what the design does not defend against, because a security page that only lists strengths is not telling you anything.

Last updated: 23 October 2026

1. The shape of a deployment

KRISID is installed inside your own environment. There is no multi-tenant service and no shared instance: one customer, one installation, one database.

ComponentWhat it is
ApplicationA single Python 3.12 service, run under systemd, listening on loopback
DatabasePostgreSQL 16 or later — your own, or a managed instance such as RDS or Cloud SQL
TLSTerminated by nginx or Caddy in front of the application
ExtensionsNone. No pgvector, no AGE, no pg_trgm — nothing for a platform team to approve
Operating systemAny current Linux; Ubuntu 24.04 and RHEL 9 are what we run

The application speaks plain HTTP on 127.0.0.1 and is designed to keep doing so. TLS, client certificates, IP allow-listing, WAF rules and SSO at the edge are all your reverse proxy's job, where your existing standards already apply.

2. What leaves your network

Nothing goes to us. There is no telemetry, no usage reporting, no licence check over the network, no crash reporting and no update check. The repository holds descriptions of your data, and often that metadata is itself regulated — a product that quietly exported it would be unusable in the sectors we work in.

Outbound connections exist only where you configure them, and only to systems you name:

  • The sources you connect for harvesting — Snowflake, Databricks, Microsoft Fabric, Power BI, Tableau, an OpenLineage endpoint
  • An SMTP server you supply, for invitations and notifications
  • Any webhook a workflow action calls, which is a named connection you create

Harvesting reads metadata — names, structures, comments, tags, row counts and the like. Connector credentials are yours and scoped by you; we recommend a read-only role.

3. Identity and sessions

The only way in is a password and a session. An earlier development header that could assert an identity was removed, and the verify suite checks that it no longer changes anything even when presented alongside a real session.

  • Passwords are hashed with scrypt — N=214, r=8, p=1 — salted per person, using the standard library rather than a third-party dependency. They are hashed, not encrypted: one-way, and unreadable even to somebody holding every key the application has.
  • Session and invite tokens are never stored. Only their hashes are. A database dump does not yield a usable session.
  • Signing out ends a session; sessions expire; changing a password requires the old one and ends every other session for that person.
  • An invitation sets a password once, and a short password is refused.
  • Switching a person off ends their sessions, and nobody can do it to themselves.

The built-in administrator ships with a known password and the application warns on screen for as long as it remains unchanged. The seeder never resets it afterwards.

4. Authorisation

Permissions are held either over the repository or over a particular asset through a role on a domain, so a domain owner decides for everything that domain owns. Every write goes through the same checks regardless of whether it came from a screen, the API or a workbook upload — the verify suite tests the screen path and the write path separately for exactly this reason.

Where a workflow governs an asset type, an edit becomes a change request rather than a write, and applying an approved request runs as the workflow rather than as the approver, so every database-level refusal still fires. Four eyes can refuse the person who raised a request even when they hold the deciding role, and an approval is refused outright if the value moved after the request was raised.

A “view as” facility lets an administrator see what somebody else sees; while it is active every write is refused.

5. Secrets

One secret has to be presented to another system rather than verified — the SMTP password — so it cannot be hashed. It is encrypted, and the key lives outside the database, in KRISID_SECRET_KEY in the service environment. If the key were in the database, a copy of the database would be a copy of the key and the encryption would be decoration.

That password is not returned by the API, not readable in the database, and decrypts only with the key held outside it. The threat this actually defends against is a dumped database, a shared backup or a screenshot of a table.

6. Audit and logging

  • Every change records the attribute, the value before and after, and the person — including who was made responsible for what, and by whom.
  • History is never trimmed. Pruning explicitly leaves it alone and says so.
  • Seven separate log channels each answer from where the fact already is, so a refused sign-in appears in the sign-in log under a person's name.
  • Tokens, cookies and passwords are stripped from everything written to the logs.
  • Logs are visible only to named readers; holding an administrative role is not sufficient on its own.

7. Licence and file integrity

Each installation carries a licence signed with Ed25519 naming your organisation and the hostnames that copy may serve. The public half is a constant in the application, so a licence cannot be forged — editing a hostname breaks the signature and the application reports it as forged rather than as valid. The check is local and per request; loopback always works, because a licence check that locks an administrator out of their own server is the outage it was meant to prevent.

manifest.json is a signed list of the SHA-256 of every shipped file. The licence screen and the doctor command compare what is on disk against it and name anything that no longer matches. This is reported, not enforced — a changed file is sometimes a support patch applied at 3 a.m. with our help. What matters is that nobody can change one quietly.

Upgrades are checked rather than asserted: the suite proves that a fresh install and an upgraded one produce an identical database — the same columns, constraints and indexes.

8. What this does not defend against

Said plainly

Somebody who already has the machine has the key file and the database both. Nothing a single-process application can do changes that, and pretending otherwise is worse than saying it.

Also worth being clear about:

  • Nothing stops a licensee redistributing the software. A contract does. Host binding and tamper-evidence raise the effort and remove deniability; they are not DRM.
  • An expired licence warns and keeps working. A hostname that is not yours means somebody moved the software; a date that has passed usually means a purchase order is slow, and taking a client's repository down over that is not something we are willing to do.
  • We have not had an external penetration test. If your procurement requires one, say so early and we will arrange it as part of the engagement rather than claim one we have not had.
  • There is no SOC 2 or ISO 27001 certification. Those certify an operator of a hosted service; KRISID runs in your environment, under your controls and your certifications. If you need evidence about our own practices as an implementation partner, ask and we will answer specifically.

9. Reporting a vulnerability

Write to contact@krisid.com with as much detail as you can. We will acknowledge it, tell you what we find, and credit you if you would like to be credited. We will not pursue anybody who reports a genuine issue in good faith, stays within their own account, and gives us a reasonable opportunity to fix it before disclosing it publicly.

Published by KRISID · 23 October 2026. The behaviours described here are checked by the product's own verification suite. Where a claim is about our practice rather than the software, it says so.