# Security

Security requirements for Anwal Growth Platform — internal business system handling CRM and email data.

## Authentication and authorization

- **NextAuth.js** (JWT session strategy) with **credentials** provider (Task 003)
- **Password storage:** bcrypt hashes in `users.passwordHash`; plain passwords never stored or returned
- **Session cookies** signed with `NEXTAUTH_SECRET`; required in all environments
- **HTTPS only** in production (`NEXTAUTH_URL`, `APP_URL` use https)
- **Inactive users:** `status: inactive` cannot sign in
- **Role-based access:** roles `admin`, `manager`, `sales`, `marketing`, `viewer` stored on user and exposed in JWT/session; enforced via `src/lib/permissions.ts` (`hasPermission`, `hasRole`, `canRead`, `canWrite`)
- **Viewer:** read-only — no `.manage` permissions; API mutation routes return `403`
- **API error handling:** production responses avoid stack traces; failures logged server-side (`src/lib/api-response.ts`)
- **Protected routes:** middleware guards dashboard and future CRM paths; unauthenticated users redirect to `/login`
- **Protected APIs:** middleware returns `401` for `/api/*` except health, auth, and bootstrap
- **Admin-only (implemented):** `/settings/*` UI and `/api/settings/**` (users, mailboxes, system, imports, AI overrides)
- **Admin-only destructive (implemented):** `/settings/data-cleanup` and `/api/admin/data-cleanup/**` — preview + exact confirmation phrase required before `deleteMany`
- **Admin-only (future):** webhook tests, broader API route guards per permission

## Bootstrap route precautions

`POST /api/admin/bootstrap` is for **local initial setup only**:

- Requires `BOOTSTRAP_SECRET` env and matching `x-bootstrap-secret` request header
- If `BOOTSTRAP_SECRET` is unset, route returns `403` (disabled)
- Uses `INITIAL_ADMIN_*` env vars; never returns passwords in response
- **Production:** disable by omitting `BOOTSTRAP_SECRET`, or restrict by network; remove or harden before public deployment
- Rotate `BOOTSTRAP_SECRET` after first use if kept enabled in staging

## Secrets management

- All credentials in environment variables — see [10-environment-variables.md](./10-environment-variables.md)
- Never commit `.env`, keys, or SMTP/IMAP passwords
- Production secrets via hosting provider (Vercel, Azure, etc.)
- Rotate credentials on staff departure or suspected leak

## Data protection

- MongoDB network restricted (IP allowlist or VPC)
- Minimum necessary fields in API responses
- Soft delete for CRM entities; hard delete admin-only with audit
- Email bodies may contain PII — restrict export to authorized roles

## Application security

- Input validation on all API routes (Zod)
- Output encoding for HTML email preview (prevent XSS)
- CSRF: NextAuth and Server Actions defaults for mutations
- Rate limit login and public tracking endpoints
- File upload: validate Excel MIME/size on import; scan if policy requires

## Email security

- SPF/DKIM/DMARC configured on sending domain (operational, not code)
- Tracking tokens: signed, expiring, non-guessable
- Unsubscribe tokens: one-click, invalidate on use
- SMTP credentials (`SMTP_USER`, `SMTP_PASS`) are server-only env vars; never exposed to client
- Click tracking redirects validate target URL schemes (`http`/`https` only; block `javascript:`/`data:`)
- Open/click tracking stores engagement events; include privacy disclosure in campaign policy
- Default IMAP/SMTP env credentials are server-only; optional per-mailbox passwords stored encrypted (AES-256-GCM keyed from `NEXTAUTH_SECRET`) and never returned in API responses
- Inbox APIs are authenticated only; unlike tracking endpoints, inbox reads and sync are not public
- Render inbound HTML bodies cautiously: `stripDangerousHtml()` removes scripts/event handlers in inbox and template preview (`src/lib/html-safety.ts`); not a full HTML sanitizer

## External AI (Task 012)

- **Server-only:** `OPENAI_API_KEY`, `GEMINI_API_KEY`, `ANTHROPIC_API_KEY` are read via `getEnv()` on the server; never bundled to the client
- **Data sent to providers:** email subject/body and minimal CRM context (company/person/campaign names) for classification only — do not include passwords, tokens, API keys, or unrelated PII
- **Fallback:** when provider fails or keys are missing, rule-based classification runs locally with no external call
- **Logging:** log error messages only; do not log full prompts, API keys, or complete email bodies in production
- **Preview API:** `/api/ai/classify-preview` is authenticated; use for testing, not for bulk export of customer data

## Webhooks

- Outbound: optional HMAC signature on payload
- Inbound n8n: shared secret header; reject missing/invalid
- No open webhooks without authentication

## Logging and monitoring

- Do not log passwords, tokens, or full email bodies in production
- Log authentication failures and webhook errors
- Alert on repeated SMTP/IMAP failures

## Compliance notes (Saudi context)

- Align with client data handling policies for government and enterprise accounts
- Document data retention for email and CRM records in settings (Task 022)
- Arabic/English content stored UTF-8

## Incident response

1. Rotate affected secrets
2. Review access logs
3. Notify Anwal leadership per internal policy
4. Document in changelog and decisions log

## Related

- [15-cursor-rules.md](./15-cursor-rules.md)
- [12-deployment.md](./12-deployment.md)
