Overview and Threat Model
Ourobor is an OSINT (Open Source Intelligence) investigation platform designed for security professionals, compliance teams, journalists, and law enforcement agencies. The nature of the data processed — investigation graphs, entity correlations, evidence artifacts, source identities, and analytical conclusions — demands a security posture that meets or exceeds the standards expected by enterprise and government clients.
What Ourobor Protects
| Asset Category | Examples | Sensitivity |
|---|---|---|
| Investigation data | Cases, queries, timelines, analytical notes | High |
| Entity correlations | Relationship graphs, link analysis, pattern matches | High |
| Evidence artifacts | Documents, screenshots, exported reports | High |
| User identities | Investigator accounts, team memberships, activity logs | Critical |
| Source information | OSINT source configs, API credentials, collection parameters | Critical |
| Organizational metadata | Billing, plan details, team structure | Medium |
Threat Actors
- External attackers. Unauthorized parties attempting to access investigation data through application vulnerabilities, credential theft, or infrastructure compromise.
- Data exfiltration. Large-scale unauthorized data access through SQL injection, API abuse, or storage misconfiguration.
- Insider threats. Malicious or negligent employees, contractors, or partners with legitimate access.
- Legal interception. Government or law enforcement requests, mitigated through jurisdictional hosting and encryption.
- Source compromise. Exposure of investigator identities or OSINT collection methods.
- Supply chain attacks. Compromise of third-party dependencies, build tools, or infrastructure providers.
Design Principles
- Defense in depth. Multiple independent layers of security ensure that compromise of any single layer does not result in a complete security incident.
- Least privilege. Every component operates with the minimum set of permissions required.
- Zero-trust architecture. Every API call is authenticated, authorized, and validated independently.
- Data minimization. Only the data necessary to deliver the service is collected and retained.
Authentication Architecture
Authentication is the first line of defense. Ourobor implements a multi-layered authentication system designed to resist credential stuffing, brute-force attacks, phishing, and session hijacking.
Password Hashing — Argon2id
All passwords are hashed using Argon2id, the winner of the Password Hashing Competition (PHC) and the OWASP-recommended algorithm. Argon2id combines side-channel resistance with GPU/ASIC resistance.
| Parameter | Value | Rationale |
|---|---|---|
| Variant | Argon2id | Hybrid: resistant to side-channel and GPU attacks |
| Memory cost | 64 MB | Ensures memory-hardness; expensive for parallel brute-force attempts |
| Iterations | 3 | Time cost balanced against latency |
| Parallelism | 4 | Matches typical server CPU core availability |
| Salt length | 32 bytes | Per-user, cryptographically random |
| Hash length | 32 bytes | 256-bit output |
Client-Side Password Hashing (Defense-in-Depth)
Before transmission, passwords are hashed client-side using SHA-256 via the Web Crypto API (crypto.subtle.digest). The server then applies Argon2id on the received SHA-256 hash, resulting in a double-hashed storage: argon2id(sha256(password)).
- Purpose: Defense-in-depth — plaintext passwords never leave the browser, even over TLS.
- Protection scope: Mitigates accidental server-side logging, TLS inspection proxies, MITM in degraded environments, and memory dumps.
- Validation: Password strength checks (12 characters minimum) are enforced client-side before hashing. The server validates the SHA-256 hex format (64 characters).
Password Policy
- Minimum length: 12 characters.
- Compromised password detection: Checked against Have I Been Pwned using k-anonymity (only 5-char SHA-1 prefix transmitted).
- No forced rotation. Consistent with NIST SP 800-63B. Rotation only on evidence of compromise.
JWT Token Architecture
Ourobor uses a dual-token system:
| Property | Access Token | Refresh Token |
|---|---|---|
| Lifetime | 15 minutes | 7 days |
| Storage | In-memory only | httpOnly Secure cookie |
| Algorithm | EdDSA (Ed25519) | EdDSA (Ed25519) |
| Rotation | N/A | Rotated on each use |
| Revocation | Stateless (short-lived) | Server-side revocation |
Refresh token rotation means a used token is immediately invalidated. Reuse of an already-rotated token triggers revocation of the entire token family, forcing re-authentication.
Multi-Factor Authentication (TOTP)
- Standard: RFC 6238 (TOTP) with HMAC-SHA1, 6 digits, 30-second step.
- Setup: QR code provisioning with manual entry fallback.
- Recovery: 12 single-use codes (128 bits entropy each), stored as Argon2id hashes.
- Enforcement: Can be required at the organization level.
Brute-Force Protection (5 Layers)
- Progressive delays: Exponentially increasing delays (1s, 2s, 4s, 8s... up to 60s).
- CAPTCHA: Required after 5 consecutive failed attempts.
- Account lockout: 30 minutes after 10 failed attempts.
- IP rate limiting: Independent per-IP limits on auth endpoints.
- Alerting: Notifications to account owner and organization admins.
Data Encryption
Ourobor applies encryption at every layer: in transit, at rest, and within the application.
Encryption in Transit
- TLS 1.3 exclusively. Older versions not supported.
- HSTS with includeSubDomains and preload directives.
- Forward secrecy via ECDHE key exchange.
Encryption at Rest — AES-256-GCM
- Algorithm: AES-256-GCM (authenticated encryption). 96-bit IV per operation.
- Scope: Entity values, evidence content, investigation queries, analytical notes.
- Key hierarchy: Master key → per-organization keys via HKDF-SHA-256 (RFC 5869).
- Key rotation: Supported without re-encrypting existing data. New records use current version; existing records re-encrypted lazily.
Database & Object Storage
- PostgreSQL TDE for filesystem-level protection.
- Encrypted backups (AES-256-GCM) with separate key management.
- WAL encryption to protect replication streams.
- Object storage with SSE and customer-managed keys (Enterprise).
Multi-Tenancy Isolation
Ensuring strict isolation between organizations is critical. A vulnerability in tenant isolation could expose one organization's investigation data to another.
PostgreSQL Row Level Security
All tenant-scoped tables enforce RLS policies at the database level. Even a SQL injection vulnerability cannot access another organization's data.
ALTER TABLE investigations ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON investigations
USING (organization_id = current_setting('app.current_org_id')::uuid);Session-Scoped Context
Tenant context is set via SET LOCAL at transaction start and automatically cleared at transaction end. No leakage between concurrent requests.
Defense-in-Depth
- Restricted database role (ourobor_app): no superuser, cannot bypass RLS.
- Application-level validation as a second independent check.
- Per-organization encryption keys: even if RLS fails, data remains encrypted with the wrong key.
API Security
Every endpoint is designed with the assumption that incoming requests may be malicious.
API Key Management
- SHA-256 hashed before storage. Full key shown once at creation, never retrievable.
- Scoped permissions: read-only, write, admin; resource-level scoping.
- Configurable expiration with audit flags for non-expiring keys.
- Instant revocation by any organization administrator.
Rate Limiting (3 Tiers)
| Level | Scope | Purpose |
|---|---|---|
| Per-IP | Source IP | Prevents distributed attacks |
| Per-user | Authenticated identity | Prevents compromised account abuse |
| Per-organization | Tenant | Prevents resource exhaustion |
Input Validation & Security Headers
- Zod schema validation at the edge, before business logic.
- Drizzle ORM parameterized queries — SQL injection eliminated by design.
- Strict CORS with origin allowlist (no wildcards).
| Header | Value |
|---|---|
| Content-Security-Policy | Strict, nonce-based script allowlisting |
| X-Frame-Options | DENY |
| X-Content-Type-Options | nosniff |
| Strict-Transport-Security | max-age=63072000; includeSubDomains; preload |
| Referrer-Policy | strict-origin-when-cross-origin |
Audit and Compliance
Ourobor is designed for European organizations operating under RGPD/GDPR.
Audit Trail
- Immutable. Append-only tables. No DELETE or UPDATE on audit records.
- Comprehensive: User, IP, timestamp, action, resource, previous/new values.
- Retention: Minimum 3 years. Configurable for enterprise.
- Exportable: JSON/CSV for SIEM integration.
RGPD Compliance
- Article 15 — Right of access: complete data export in machine-readable format.
- Article 16 — Right to rectification.
- Article 17 — Right to erasure: processed within 30 days, logged without retaining erased data.
- Article 20 — Data portability in standard formats.
- Article 30 — Records of processing activities maintained.
- Article 35 — DPIA (AIPD) maintained and reviewed annually.
Retention Policies
| Data Category | Default | Configurable |
|---|---|---|
| Investigation data | Until deleted | Yes |
| Audit logs | 3 years | Yes (min 1 year) |
| Auth logs | 1 year | Yes |
| Deleted accounts | 30 days, then purged | Yes |
| Backups | 90 days | Yes |
Infrastructure Security
Hosting & Data Sovereignty
Ourobor is hosted on Scaleway, a French sovereign cloud provider (ISO 27001, HDS, SecNumCloud by ANSSI).
Container Isolation
- Kubernetes with network policies restricting pod-to-pod communication.
- Non-root containers, read-only filesystems, privilege escalation disabled.
- CPU/memory limits enforced. Images scanned and signed.
Secrets & Vulnerability Management
- Secrets injected at runtime, never in source code or images.
- Dependabot + Snyk for continuous dependency scanning.
- Annual penetration testing by independent third party.
- Log pipeline excludes sensitive fields (password, token, key, secret, authorization).
Incident Response
Ourobor maintains a documented incident response plan.
| Phase | Target | Description |
|---|---|---|
| Detection | < 1 hour | Automated monitoring and alerting |
| Triage | < 4 hours | Severity classification, initial containment |
| Containment | < 8 hours | System isolation, credential revocation |
| CNIL notification | < 72 hours | RGPD Article 33 regulatory notification |
| User notification | < 48 hours | Article 34 for high-risk security incidents |
| Resolution | Varies | Root cause analysis, remediation |
| Post-incident review | < 2 weeks | Lessons learned, preventive measures |
Each incident produces a root cause analysis, remediation actions with owners and deadlines, and updates to monitoring and response procedures.
Secure Development
Security is integrated into every phase of the development lifecycle.
- TypeScript strict mode eliminates type confusion, null reference, and implicit coercion vulnerabilities.
- Mandatory code review with security-aware reviewers for auth/crypto changes.
- Protected main branch — no direct pushes, no force-pushes.
CI/CD Security Gates
- ESLint with security-focused rules (no-eval, no-implied-eval, no-new-func).
- Full TypeScript type-check with strict mode.
- Unit and integration tests including security-specific cases.
- pnpm audit + Snyk scanning for all dependencies.
- Automated secret scanning on every commit.
Dependency Management
pnpm provides strict dependency resolution (no phantom dependencies) and an immutable lockfile. Dependencies are reviewed for security posture before adoption.
Cryptographic Primitives Summary
All cryptographic implementations use well-audited libraries. No custom cryptographic code is used.
| Purpose | Algorithm | Parameters | Standard |
|---|---|---|---|
| Password hashing (server) | Argon2id | 64 MB, 3 iter, 4 par, 32B salt/hash | RFC 9106 |
| Password hashing (client) | SHA-256 | 256-bit digest, pre-transit | Web Crypto API / FIPS 180-4 |
| Token signing | EdDSA (Ed25519) | 256-bit key | RFC 8032 |
| Data encryption | AES-256-GCM | 256-bit key, 96-bit IV, 128-bit tag | NIST SP 800-38D |
| Key derivation | HKDF-SHA-256 | Per-org context, 256-bit output | RFC 5869 |
| MFA | TOTP (HMAC-SHA-1) | 6 digits, 30s step | RFC 6238 |
| Random generation | crypto.randomBytes | OS CSPRNG | NIST SP 800-90A |
| API key hashing | SHA-256 | 256-bit digest | FIPS 180-4 |
| Transport | TLS 1.3 | ECDHE, forward secrecy | RFC 8446 |