# CHIMBO Security Model

This document describes production security controls. It contains **no secrets**.

## Authentication

- Passwords: Argon2id (`src/features/auth/password.ts`).
- Sessions: opaque 256-bit tokens; only SHA-256 digests stored (`Session.tokenHash`).
- Cookies: production uses `__Host-chimbo-session` with `HttpOnly`, `Secure`, `SameSite=Lax`, `Path=/`.
- **Cookie scope decision:** host-only (`__Host-`). Auth cookies are **not** shared to tenant subdomains (`*.ROOT_DOMAIN`). Tenant storefronts never receive privileged session cookies.
- Session lifetime: 7 days; logout deletes the digest and clears the cookie.
- Disabled users (`disabledAt`) cannot authenticate; sessions are revoked on user suspend.
- Password reset: single-use hashed tokens, 30-minute expiry; SMTP required or recovery returns 503.

## Authorization

- Tenant mutations require `requireBusiness(businessId, permission)` after membership lookup.
- Super Admin mutations require `requireSuperAdmin()` / `loadSuperAdmin()` — never UI hiding alone.
- Role mass-assignment is rejected by Zod schemas (`platformRole` cannot be client-set).

## CSRF

- State-changing JSON APIs use `assertOrigin` / `readJson` against `APP_URL`.
- Public offer interest additionally allows Origins on valid `{slug}.{ROOT_DOMAIN}` hosts (same scheme as `APP_URL`).
- Broker offer convert/cancel use the same Origin checks.
- Content-Type must be `application/json`; bodies capped (16 KiB for typical auth/mutations).
- SameSite=Lax cookies reduce cross-site POST cookie attachment.

## Multi-tenancy

- Tenant hosts resolved from validated `Host` vs `ROOT_DOMAIN` only — never `X-Forwarded-Host`.
- Tenant hosts cannot access `/dashboard`, `/api` (except `/api/public/`), `/super-admin`, or auth routes.
- Unknown hosts → 421.
- Composite uniqueness and indexes include `businessId` on tenant data.

## Rate limiting

- DB-backed HMAC buckets (`RATE_LIMIT_SECRET`).
- Client key: Cloudflare `cf-connecting-ip` only when `TRUST_CLOUDFLARE=true` and IP validates; otherwise shared `untrusted-network` (conservative).
- Applied to auth, public interest, billing, admin, and creation endpoints.

## Uploads / images

- No arbitrary file upload endpoint in this release.
- Product `imageUrl` must be **HTTPS** only (validated server-side).

## Payments

- Plan prices are server-authoritative; clients cannot supply price.
- Activation requires verified provider events (or explicitly gated dev adapter — **disabled in production**).
- No admin payment Failed→Succeeded dropdown.

## Headers

- CSP with per-request nonce + `strict-dynamic`
- `X-Content-Type-Options: nosniff`
- `Referrer-Policy: strict-origin-when-cross-origin`
- `Permissions-Policy` (camera/mic/geo/payment/usb disabled)
- `X-Frame-Options: DENY`
- Production `Strict-Transport-Security` with `includeSubDomains` (requires valid HTTPS on all subdomains)
- Private routes: `Cache-Control: private, no-store` and `X-Robots-Tag: noindex`

## Secrets

- Store in environment / secret manager only.
- Never commit `.env` (see `.gitignore`).
- Platform settings UI cannot store keys containing `secret`/`key`/`password`.

## Incident basics

1. Rotate `RATE_LIMIT_SECRET` and session secrets if compromised; revoke sessions (`DELETE FROM Session`).
2. Suspend affected businesses/users via Super Admin with reason + audit.
3. Preserve audit logs; do not truncate as “cleanup.”
4. Restore from encrypted off-host backup if integrity is uncertain (see `DEPLOYMENT.md`).

## Reporting

Email the support address configured in platform settings / operations runbook. Do not include customer passwords or payment card data in tickets.
