This page describes the security architecture of KaireonAI as it is implemented today. Where a capability is planned but not yet shipped, it is marked explicitly.Documentation Index
Fetch the complete documentation index at: https://docs.kaireonai.com/llms.txt
Use this file to discover all available pages before exploring further.
Tenant Isolation
KaireonAI is multi-tenant by default. Every database record includes atenantId column, and every API query is scoped to the authenticated tenant.
Application-Layer Filtering
All database access flows through a tenant-scoped data layer that automatically constrains every query to the authenticated tenant:- The query layer rejects any read or write that lacks an explicit tenant filter, so a missing tenant clause becomes a server-side error rather than a cross-tenant data leak.
- Read, create, update, and delete operations against tenant-scoped tables are wrapped to inject the tenant ID before the query runs, so application code cannot accidentally widen the scope.
403 Forbidden.
Optional Row-Level Security (RLS)
For deployments that require database-level isolation as a second boundary, KaireonAI ships an admin API (POST /api/v1/admin/rls) that creates PostgreSQL RLS policies on all tenant-scoped tables. RLS is opt-in because it requires superuser privileges on the database and adds a small query overhead.
Single-Tenant Mode
Self-hosted deployments can setSINGLE_TENANT_MODE=true to bypass multi-tenant resolution. In this mode, all data belongs to a single default tenant and the tenant resolution middleware is skipped.
Authentication
KaireonAI supports three authentication methods, each suited to a different integration pattern.Browser Sessions (NextAuth)
Interactive users authenticate via NextAuth.js sessions:- Google OAuth — one-click sign-in, automatic email verification.
- Email and password — bcrypt-hashed passwords, email verification flow, password reset via time-limited tokens.
userId, tenantId, and role.
MFA (TOTP) — precise status. TOTP endpoints at
/api/v1/auth/mfa
(setup, enable, verify, disable) are implemented and functional per
RFC 6238. Secrets are encrypted at rest, backup codes are one-way-hashed,
token comparison is timing-safe, and the verify path is rate-limited.
Session-level enforcement is not yet active: the middleware enforcement
hook exists but is commented out because session.mfaVerified is hardcoded
to false — wiring a verify-to-session update flow so middleware can gate
protected routes is the remaining work.WebAuthn (FIDO2 hardware-backed MFA) — shipped 2026-05-03. Four
HTTP routes implement the standard WebAuthn ceremonies. Registration
uses
POST /api/v1/auth/webauthn/register/begin followed by
POST /api/v1/auth/webauthn/register/finish; sign-in uses
POST /api/v1/auth/webauthn/verify/begin followed by
POST /api/v1/auth/webauthn/verify/finish. Challenges are persisted
in Redis with a 60-second TTL and consumed atomically (GETDEL) keyed
by user and ceremony purpose, so replays of /finish fail closed.
Registration verifies the client-data round-trip (type,
challenge, origin); verification re-checks the assertion
signature with a full COSE-key parse supporting ES256 and RS256, and
rejects assertions whose authenticator counter has not advanced
(monotonic-counter replay defence). Enrolled credentials are stored
per user. The four-eyes admin enrolment flow is the compensating
control for V1’s attestation: "none" acceptance — attestation
conveyance is V3.API Keys (Server-to-Server)
For programmatic access, users generate API keys from the Settings page. Keys are prefixedkrn_ for easy identification in logs.
- Keys are stored as one-way HMAC-SHA256 hashes — the raw key is shown once at creation and cannot be recovered.
- Each key is bound to a specific tenant. The
X-Tenant-Idheader is ignored when authenticating via API key to prevent tenant spoofing. - Keys support optional scopes (read-only, write, admin) and expiration dates.
Internal Service Tokens
For internal service-to-service calls (e.g., pipeline workers, cron jobs), the platform accepts a shared INTERNAL_SERVICE_SECRET validated via constant-time comparison. This token bypasses session lookup and is intended for trusted infrastructure only.CSRF Protection
KaireonAI uses a dual-strategy CSRF model:| Client Type | Protection Mechanism |
|---|---|
| Browser (UI) | A custom X-Requested-With header is required on all mutating requests. The browser’s same-origin policy prevents cross-origin scripts from setting custom headers, so a forged request from another origin cannot satisfy this check. |
| Server-to-server | API key in Authorization header. No CSRF risk because there is no ambient credential (no cookie). |
X-Requested-With check is enforced in the API middleware layer. Requests without this header or a valid API key are rejected with 403.
This is a standard defense — the same approach is used by Django, Rails, and Angular. It relies on the browser refusing to attach custom request headers on cross-origin requests, which is enforced by the same-origin policy in all modern browsers.
SSRF Protection
Server-Side Request Forgery (SSRF) is a significant risk because KaireonAI makes outbound HTTP calls in several places: webhook delivery, REST API connectors, CMS content sync, external ML scoring endpoints, alert notifications, and trigger engine webhooks.Two-Layer Validation
-
Hostname check (synchronous) — Outbound URLs are first screened against a deny list of known-bad hostnames (
localhost,metadata.google.internal,169.254.169.254) and private IPv4/IPv6 ranges (10.x,172.16-31.x,192.168.x,127.x,::1,fc00::/7,fe80::/10). - DNS resolution check (async) — The platform then resolves the hostname via DNS (both A and AAAA records) and verifies that every resolved IP is outside private ranges before issuing the request. This prevents DNS rebinding attacks where a hostname initially resolves to a public IP during validation but later resolves to a private IP.
Protected Code Paths
The full DNS-resolution check runs before any outbound HTTP call from the following surfaces:- Outbound webhook delivery
- REST API connectors used by data pipelines
- External ML scoring endpoints
- CMS content sync (every adapter URL is validated)
- Alert notification webhooks
- Trigger-engine webhooks
Self-Hosted Recommendation
If you run KaireonAI on a private network, consider adding an egress proxy (e.g., Squid, Envoy) that restricts outbound traffic to known-good destinations. The application-level SSRF check is a strong default, but an egress proxy provides defense in depth at the network layer.Rate Limiting
KaireonAI includes a sliding-window rate limiter with two storage backends:- In-memory — suitable for single-process deployments. Tracks request timestamps per key and rejects when the count exceeds the configured limit within the window.
- Redis-backed — uses sorted-set sliding window (zadd + zremrangebyscore + zcard) for consistent rate limiting across multiple Node.js processes.
- Journey callback endpoints
- The Recommend API (configurable per deployment)
For DDoS protection, we recommend using edge-level rate limiting (AWS WAF, Cloudflare rate rules, or nginx
limit_req_zone) in addition to the application-level limiter.Encryption at Rest
Connector Secrets
All sensitive connector credentials (database passwords, API tokens, OAuth client secrets) are encrypted with AES-256-GCM before storage. Each record uses a unique initialization vector (IV) and authentication tag. The encryption key is derived from the CONNECTOR_ENCRYPTION_KEY environment variable. Self-hosted deployments must set this to a cryptographically random 32-byte hex string.API Key Hashing
Platform API keys (krn_ prefix) are stored as one-way HMAC-SHA256 hashes. The raw key is displayed once at creation and cannot be recovered from the database.
Password Hashing
User passwords are hashed with bcrypt (cost factor 12) before storage.Audit Logging
Every mutating operation is recorded in an immutable audit log with:- Tenant ID, user ID, action, entity type, and entity ID
- Before-and-after JSON snapshots (for update operations)
- The originating IP address and user agent
- A server-assigned timestamp
GET /api/v1/audit-logs (paginated JSON, suitable for SIEM forwarders that poll an HTTP source).
LLM Explanation Safety
KaireonAI can generate natural-language explanations of individual decisions viaPOST /api/v1/decisions/:id/narrative. Because these explanations are
sent to an external LLM provider, the feature has several defense layers:
- Per-tenant opt-in — Disabled by default. The flag
tenantSettings.aiAnalyzerSettings.llmExplanationsEnabledmust be set totruebefore any narrative is produced. A 403 response is returned otherwise. - PII redaction — Customer attributes are stripped of personally identifiable fields before the request body is assembled. The prompt sent to the LLM only contains offer IDs, feature contributions, and policy reasons, not raw customer fields.
- Audit log for regulator mode — When
mode = "regulator", the handler writes a dedicated audit-log entry (actiongenerate_narrative, entity typedecision_trace) capturing the mode, model, cache-hit flag, and the first 200 characters of the narrative. This supports DSAR exports and compliance review. - Out-of-band from /recommend — Narrative generation runs only on demand
against the persisted decision-trace record for a previously made decision.
It never executes during a
/recommendcall, so LLM latency or availability cannot affect decisioning. - Rate limited — 20 narrative requests per minute per tenant.
- Cached — Results are cached in Redis for 7 days keyed by
(tenantId × decisionTraceId × mode × model × inputsHash), so repeat requests for the same trace do not hit the LLM again.
Input Validation
All API request bodies are validated with Zod schemas before processing. Invalid requests are rejected with400 Bad Request and a structured error response listing the validation failures.
The formula engine uses a custom recursive-descent parser — dynamic code execution via eval or constructor-based evaluation is never used.
External content IDs (for example, CMS entry IDs) are sanitized to the character set [a-zA-Z0-9._-] before being used in any downstream call or storage path.
Webhook Signature Verification
Inbound webhooks (from CMS providers, payment systems, etc.) are verified using HMAC-SHA256 signature validation with constant-time comparison to prevent timing attacks. The signing secret is configured per integration. Outbound webhooks sent by KaireonAI include anX-Kaireon-Signature header containing a sha256= prefixed HMAC, allowing recipients to verify authenticity.
What Users Should Configure
For a production deployment, ensure these are set:| Setting | Purpose |
|---|---|
| CONNECTOR_ENCRYPTION_KEY | AES-256 key for connector secret encryption (32-byte hex) |
NEXTAUTH_SECRET | Session signing key for NextAuth.js |
WEBHOOK_SIGNING_SECRET | HMAC key for outbound webhook signatures |
| INTERNAL_SERVICE_SECRET | Shared secret for internal service-to-service auth |
DATABASE_URL | PostgreSQL connection string (use SSL in production) |
| TLS termination | Configure at load balancer or reverse proxy |
| Edge rate limiting | AWS WAF, Cloudflare, or nginx for DDoS protection |
| Egress proxy | Optional — restrict outbound traffic from the application |
Planned Enhancements
The following capabilities are on the roadmap but not yet fully implemented:- Multi-factor authentication (session enforcement) — TOTP endpoints (
setup/enable/verify/disable) at/api/v1/auth/mfaare implemented per RFC 6238 with encrypted secrets, hashed backup codes, timing-safe verification, and rate-limiting. Session-level enforcement in middleware is staged but not yet active becausesession.mfaVerifiedis hardcoded tofalse; a verify-to-session update flow is the remaining work. WebAuthn is planned. - OAuth 2.0 provider — Allow external applications to authenticate via OAuth flows
- SCIM provisioning — Automated user provisioning from identity providers
- Field-level encryption — Encrypt sensitive customer data fields at the application layer
- IP allowlisting — Restrict API key usage to specific IP ranges