Security
How Vessios isolates tenants, protects data, and defends against common attack paths.
Vessios is multi-tenant SaaS, so tenant isolation and defense against common attack classes are foundational, not add-ons.
Tenant isolation
Every tenant’s pages, sources, and knowledge graph live in isolated subcollections. Isolation in vector search is deterministic — enforced by a tenant_id category restriction, not by a hash function that could theoretically collide. Content flagged as containing PII risk during ingest is excluded from every search path (vector, keyword, and agentic) until an admin reviews it, so it never reaches an LLM prompt unreviewed.
Authentication & authorization
- JWT-based sessions (RS256-signed, 1-hour access tokens, 30-day refresh tokens).
- Role-based access control with four roles —
owner/admin/editor/viewer— see Quickstart for what each can do. - Role changes cannot be applied to yourself, preventing accidental or malicious self-escalation.
- Token revocation (JTI) and password-reset rate limiting are fail-closed: if the underlying cache is unavailable, Vessios denies rather than silently allowing the request.
Ingest-time defenses
- SSRF protection on every URL ingest and every webhook/connector target — internal and unexpected hosts are rejected before any request is made.
- Duplicate detection via SHA-256 content hashing.
- Prompt-injection screening on ingested content, and quarantine of injected instructions detected in retrieved content at query time.
- Deterministic output filtering — generated answers are blocked from exfiltrating data to external URLs.
- Agentic search’s LLM-generated regular expressions run under bounded match-length and scan-line budgets to prevent ReDoS.
Billing & idempotency
Stripe webhook events are verified against the raw request body using HMAC-SHA256 before being trusted. Idempotency (for both ingest requests via X-Idempotency-Key and Stripe events) uses an atomic claim (SET NX) so concurrent duplicate requests can’t both apply. Billing events specifically use a fail-closed claim: if the underlying store is unavailable, Vessios returns a retryable error so Stripe retries later, rather than risking a double-applied charge or entitlement change.
Data lifecycle
- Full tenant deletion is available for GDPR compliance (
DELETE /tenants/me). - Page history is versioned with optimistic locking, so pages can always be inspected and restored.
Production safeguards
Vessios refuses to start in production with an insecure configuration: it rejects local-only fallbacks (like an in-memory cache standing in for Redis) and Stripe test keys, and it requires critical secrets (webhook signing secrets, internal service secrets, and an explicit CORS allow-list) to be set — an incomplete configuration fails the deployment rather than degrading silently.