Spaces:
Running
Running
|
Download docs/security.md from Benaah/MicProtocol: direct link, hf CLI and curl.
- Browser
- Download file 11 kB
-
https://huggingface.co/spaces/Benaah/MicProtocol/resolve/main/docs/security.md
- Command line
-
hf download hf://spaces/Benaah/MicProtocol/docs/security.md
-
curl -L -o security.md https://huggingface.co/spaces/Benaah/MicProtocol/resolve/main/docs/security.md
11 kB
| # Security & Compliance | |
| This doc covers the security model, threat surface, and regulatory compliance posture of MicProtocol. It complements [Webhooks](./webhooks.md) (per-webhook auth) and [Operations Runbook](./operations-runbook.md) (incident response). | |
| ## Authentication | |
| - **Provider**: Better Auth β handles session management, OAuth (Google, Apple), password hashing, email verification, and device sessions. | |
| - **Tokens**: Session cookie `better-auth.session_token` (httpOnly, SameSite=Lax). Verified by `BetterAuthGuard` on every protected endpoint via `BetterAuthService.getSessionFromHeaders()`. | |
| - **Workspace scoping**: Resolved from the authenticated user's `WorkspaceMember` memberships; the `hasWorkspace` tRPC middleware enforces the required role. | |
| - **Dev mode bypass**: If `DEV_AUTH_BYPASS_ENABLED=true` and `NODE_ENV=development`, the API accepts an `x-user-id` header containing a user UUID. Used by the synthetic agent runner and local dev. **Never expose this in production** β the auth guard rejects it unless both conditions are met. | |
| - **Webhook secret**: Not applicable to Better Auth β user lifecycle events are handled via the `Session`/`Account`/`Verification` Prisma models directly. | |
| - **OAuth flows**: Google Calendar (`GOOGLE_CLIENT_*`), Nylas (`NYLAS_CLIENT_*`) for Google/Outlook/Exchange, with explicit redirect URIs in `.env`. | |
| ## Authorization | |
| - **Role hierarchy**: `Owner > Admin > Editor > Viewer`. Workspace-level role assignment via `WorkspaceMember.role`. | |
| - **Scope**: Every domain query chains through `workspace β podcast β entity`. The synthetic agent suite explicitly tests cross-workspace isolation in [`scripts/synthetic-agents/scenarios/cross-workspace.ts`](../scripts/synthetic-agents/scenarios/cross-workspace.ts). | |
| - **Guest portal**: signed-token auth (HMAC-SHA256 with a workspace-specific secret, 7-day expiry, granular scope). No tenant-level access from guest tokens. | |
| ## Transport Security | |
| - **TLS 1.3** minimum on all production connections (enforced by Clerk, Resend, R2, Nylas; verify at your reverse proxy). | |
| - **HSTS** with preload β set on the edge proxy serving web + guest portal. | |
| - **WS auth**: WebSocket connections require a JWT in `Authorization` (Socket.io) or a JWT signed with `MIC_REALTIME_SHARED_SECRET` (mic-realtime). | |
| - **Socket.io `/events` hardening**: handshake origins follow the same policy as HTTP CORS (`common/origin-policy.ts` β explicit origins + `*.ROOT_DOMAIN` subdomains), incoming message payloads are capped at 64 KB, `join:*` payloads are shape-validated, and per-socket join rate limiting (30/min) bounds DB lookups. | |
| ## Data Isolation | |
| | Layer | Mechanism | | |
| |---|---| | |
| | Application | Every query filters `podcastId β workspaceId`; no cross-workspace join possible from the API code path | | |
| | Database | Row-Level Security (RLS) enabled on tenant-scoped tables (`workspaces`, `workspace_members`, `podcasts`, `diaries`, `workspace_branding_settings`, `workspace_settings`, `workspace_integrations`, `conversations`, `tasks`, `media_comments`). Policies scope rows to `current_setting('app.workspace_id', true)::uuid`. Set via `RLSMiddleware` on each authenticated request. Migration: `20261023000001_enable_rls`. | | |
| | Object storage | Per-tenant prefixes in the shared `micprotocol-storage` bucket; presigned URLs with 15-minute expiry | | |
| The `workspace β podcast β guest` hierarchy is the foundation of complete data isolation. See [Database Schema β Row-Level Security](./database-schema.md#row-level-security-rls-policy). | |
| ## Secrets Management | |
| - **Single source of truth**: `.env` (never committed; `.gitignore` excludes it). | |
| - **Generation**: `bash scripts/generate-secrets.sh` produces strong random values for every required secret. | |
| - **Rotation policy**: | |
| - **Never rotate after initial setup**: every `*_ENCRYPTION_KEY`, `*_NEXTAUTH_SECRET`, `CALCOM_ENCRYPTION_KEY`, `DOCUMENSO_ENCRYPTION_KEY/SECONDARY_KEY`, `FORMBRICKS_ENCRYPTION_KEY`, `FORMBRICKS_HUB_API_KEY`, `FORMBRICKS_CUBE_API_SECRET`. Rotation invalidates all encrypted data and sessions. | |
| - **Rotatable on a schedule**: `*_WEBHOOK_SECRET`, `FORMBRICKS_CRON_SECRET`, `UMAMI_APP_SECRET`, Mongo/Redis passwords, SMTP credentials. | |
| - **Rotatable via UI**: per-integration admin tokens (`CALCOM_API_KEY`, `FORMBRICKS_API_KEY`, `LISTMONK_API_TOKEN`, `CHATWOOT_API_KEY`). | |
| - **Production**: store in AWS Secrets Manager or equivalent; inject at container start, never bake into images. | |
| ## File Uploads | |
| | Concern | Implementation | | |
| |---|---| | |
| | Access | Presigned R2/MinIO URLs, 15-minute expiry, single-use | | |
| | MIME verification | `Content-Type` checked against allowlist on ingest | | |
| | Virus scanning | ClamAV scan on ingest (see deployment architecture doc) | | |
| | Size limits | Enforced at the proxy and in the upload handler | | |
| | Storage class | R2 Standard by default; lifecycle rules for archival if needed | | |
| See [Architecture β Data Security](./design.md#91-data-security). | |
| ## Rate Limiting | |
| Redis-backed rate limiter with two tiers: | |
| | Scope | Limit | Configurable via | | |
| |---|---|---| | |
| | Per IP (anonymous + guest portal) | 100 req/min | `RATE_LIMIT_TTL`, `RATE_LIMIT_MAX` | | |
| | Per authenticated workspace | 1000 req/min | tRPC rate-limit middleware | | |
| | Per WebSocket | 120 messages/min | `MIC_REALTIME_RATE_LIMIT` | | |
| 429 responses include a `Retry-After` header. Synthetic agents surface rate-limit gaps in [`weaknesses.json`](../scripts/synthetic-agents/weaknesses.json). | |
| ## Logging & Audit | |
| - **Audit log**: every write operation emits an audit event to an append-only `audit_logs` table (per SOC2 CC6). Implemented via `AuditService` (best-effort writes, never blocks the request path). Migration: `20261023000000_add_audit_log`. | |
| - **Trace propagation**: `X-Trace-Id` (`tr-xxxxxxxx`) crosses services and clients; `X-Response-Time` carries duration. | |
| - **Telemetry endpoints**: `/tracing/spans` (recent spans + p95), `/tracing/metrics` (counts, error rate). Surfaced in the Admin app at `/monitoring` and `/analytics`. | |
| - **No PII in logs**: the logger redacts known PII fields (email, phone) before emitting. | |
| - **Integrations**: optional Sentry (`SENTRY_DSN`) and LogRocket (`LOGROCKET_APP_ID`) for error tracking and session replay. | |
| ## Privacy & Compliance | |
| MicProtocol is built to comply with **GDPR (EU)**, **POPIA (South Africa)**, **Kenya DPA 2019**, and **Nigeria NDPR**. Features supporting these regimes: | |
| | Requirement | Implementation | | |
| |---|---| | |
| | Right to erasure | Cascade workflow that anonymises guest PII across episodes, messages, and assets while preserving aggregate analytics | | |
| | Data minimisation | Only fields required for outreach and booking are collected; open-ended custom fields lock behind workspace admin approval | | |
| | Consent tracking | Outreach sequences record processing basis (legitimate interest) and flag sequences where unsubscribe was received | | |
| | Email compliance | CAN-SPAM footer injection, `List-Unsubscribe` headers, automatic unsubscribe on `.unsubscribe` event | | |
| | Data residency | Workspace billing tier unlocks the ability to specify R2 storage region (incl. `Africa South / Johannesburg` edge) | | |
| | Breach notification | Operational runbook covers incident communication (see [Operations Runbook](./operations-runbook.md)) | | |
| ## Mobile-Specific Security | |
| - **Certificate pinning** on all API calls (configurable per environment). | |
| - **Secure storage**: Keychain (iOS) / Keystore (Android) for tokens and secrets. | |
| - **Biometric authentication** (FaceID/TouchID) opt-in. | |
| - **Jailbreak/root detection** β refuses to run on compromised devices in production builds. | |
| - **Obfuscation** ready for production builds (EAS Build). | |
| See [`apps/mobile/FEATURES.md`](../apps/mobile/FEATURES.md) for the full mobile security checklist. | |
| ## Webhook Security | |
| Every inbound webhook uses `crypto.timingSafeEqual()` for HMAC signature verification β no timing side-channels. See [Webhooks β Security Model](./webhooks.md#security-model) for the catalog and the per-provider checklist. LiveKit is the exception: it authenticates via a Bearer JWT (`iss` = `LIVEKIT_API_KEY`, HS256 with `LIVEKIT_API_SECRET`) whose `sha256` claim is verified over the raw request body. | |
| Critical production safeguards: | |
| 1. Set every `*_WEBHOOK_SECRET` (empty values silently disable verification). | |
| 2. Sync secrets on both sides when rotating. | |
| 3. Restrict by source IP where the upstream publishes known egress ranges. | |
| 4. Monitor 401 rates from the webhook controller. | |
| 5. Never expose webhooks over plain HTTP. | |
| ## Vulnerability Detection | |
| The synthetic agent framework ([`scripts/synthetic-agents/`](../scripts/synthetic-agents/)) continuously probes the API surface for known weakness categories: | |
| - Auth guard gaps (missing role checks) | |
| - Input validation failures (Zod schema mismatches, type coercion) | |
| - Rate limit gaps (per-IP vs per-workspace) | |
| - Subscription gating failures (paid features reachable on free tier) | |
| - Privilege escalation (viewer β admin) | |
| - Workspace boundary leaks | |
| Run a full sweep before any release: | |
| ```bash | |
| pnpm agents:run | |
| ``` | |
| Findings categorised by severity in `scripts/synthetic-agents/weaknesses.json`. See the [Synthetic Agents Testing](./INDEX.md#synthetic-agents-testing) section of the docs index. | |
| ## Known Threats & Mitigations | |
| | Threat | Mitigation | | |
| |---|---| | |
| | Token enumeration on guest portal | Per-IP rate limit (10 req/min) on `/portal/*` | | |
| | Cross-workspace data leak | `workspaceId` filtering in every query handler; RLS at DB layer | | |
| | Webhook replay | `WebhookIdempotencyService` dedupes via deterministic event keys | | |
| | Route shadowing (duplicate endpoint) | `RouteCollisionService` fails API startup when two handlers register the same method + path | | |
| | Subprocess injection (CLIP scorer) | `execFile` with argv (no shell); `assertSafeUrl` validates the video URL before download | | |
| | Secrets in client bundles | Only `NEXT_PUBLIC_*` vars exposed to web; all others server-side only | | |
| | CSRF on mutations | tRPC + SameSite cookies; Better Auth session cookie defaults | | |
| | Server-side request forgery | `apps/api/src/common/safe-fetch.ts` validates URLs against an allowlist before fetch | | |
| ## Security Checklist for Releases | |
| | Stage | Check | | |
| |---|---| | |
| | Pre-merge | `pnpm agents:run` passes; no new entries in `weaknesses.json` | | |
| | Pre-deploy | All `*_WEBHOOK_SECRET` set; no `*_ENCRYPTION_KEY` is empty; `BETTER_AUTH_SECRET` set; `MIC_REALTIME_*_SECRET` set | | |
| | Post-deploy | `/health/detailed` returns green; `/integrations/health` returns green for every integration in use | | |
| | Quarterly | Rotate webhook secrets; review `audit_log` for anomalies; test backup restoration | | |
| | Annually | Penetration test webhook + portal endpoints; review access logs for stale service accounts | | |
| ## Reporting Vulnerabilities | |
| Internal reports: file a security-labeled issue in the repo with reproduction steps. External reports (researchers): contact the platform team via the security contact in the Admin app. | |