Security
What is actually enforced
Every control on this page is implemented in the Vorkhurry codebase. Where something is a design decision rather than a guarantee, it is written as one.
Threats and the controls against them
The same table the engineering team keeps, written out rather than summarised into adjectives.
| Threat | Control |
|---|---|
| Cross-tenant read or write | Tenant scoping lives in one repository base class rather than in several hundred query filters, with PostgreSQL row-level security as a second, independent backstop. Escaping either requires an explicitly named context manager that logs a warning, and a cross-tenant read answers 404 rather than 403 — a 403 would confirm the row exists. |
| Privilege escalation | Permissions are data in the database, checked server-side in the service layer — never only in the interface. A role change invalidates the cached permission set rather than waiting for it to expire. |
| Token theft | Access tokens are short-lived and signed with rotating keys, so a key can be retired without invalidating every session at once. Refresh tokens rotate on use, and a reused one revokes the whole family. Sessions are device-bound, listable, and individually revocable. |
| Token exposure to scripts | Both tokens live in HttpOnly cookies set by the application's own route handlers; browser code never reads them. The one deliberate exception is the WebSocket ticket, because the browser's WebSocket constructor cannot set headers — it hands out the short-lived access token only, never the refresh token. |
| Cross-site request forgery | SameSite cookies plus a double-submit token on cookie-authenticated routes. |
| Cross-site scripting | React escaping, content sanitised server-side on write, and a strict content security policy. Search snippets are parsed rather than injected: the server's highlight markup is split and rendered as text nodes, so no path reaches innerHTML. |
| SQL injection | Parameterised queries only. No SQL is built by string concatenation. |
| Brute force and abuse | Redis sliding-window rate limits per caller, with tighter classes on the routes that need them — authentication and search are limited far below the default. |
| Secret leakage | Secrets come from the environment or a secret manager and are never committed. Integration credentials and AI provider keys are encrypted at rest with Fernet and are never returned by the API. Structured logs redact by key name. |
| Repudiation | An append-only audit log records the actor, their address and user agent, and what changed — for organization settings, membership, roles, permission overrides, invitations and ownership transfer. |
Authentication
Passwords are hashed with Argon2id. Two-factor is TOTP with recovery codes. Magic links are single-use. Where a deployment configures them, Microsoft and GitHub OAuth are available. Every session is device-bound; you can list your sessions and revoke one.
Authorization
146 named permissions, grouped by area, with the ones that let a holder escalate their own access or read sensitive personal data flagged as dangerous and audited when granted. Roles carry no hierarchy — a role is exactly the permissions granted to it — and an effective-permission view resolves roles, groups and overrides into one answer.
Integration and AI credentials
GitHub is connected as an app: only the installation id is stored, and every call mints a token that expires in an hour. Chat and AI credentials are encrypted at rest, and the API returns a masked suffix rather than the value. Inbound webhooks are signature-verified and recorded once, so a redelivery is acknowledged rather than applied twice.
In the pipeline
- CodeQL — Security-extended query suite. Gating.
- Architecture contracts — Layering violations fail the build, not a lint warning.
- Dependency audits — pip-audit and npm audit run weekly, alongside Dependabot.
- Migration round-trip — Every migration is applied and reversed in CI.
- Isolation test suite — Cross-tenant access is tested, not assumed.
What we do not claim
Vorkhurry holds no security or compliance certifications, and this page carries no badges for that reason. It makes no uptime guarantee, because one that is not measured and contractual is a decoration. Nothing here should be read as a substitute for your own assessment.
If you believe you have found a security issue, please write to contact@vorkhurry.com rather than opening a public issue.
Start with your team, not with a sales call
Create a workspace, invite the people you work with, and bring your existing issues in from Jira, Linear or a CSV.