# Security

## Reporting

Report vulnerabilities to **andikadebiputra@gmail.com**. Please do not open public issues for security problems.

We aim to acknowledge within 48 hours and to ship a fix or mitigation for critical issues within 7 days.

---

## Supply Chain — Known Advisories (as of 2026-05-15)

### Backend (`composer audit`)

- **No vulnerability advisories.**
- `laragear/webauthn` is marked **abandoned**. Replacement: `laravel/passkeys`. Migration planned for a separate change since the public surface differs.

### Frontend root (`npm audit`)

- **No vulnerabilities.**

### Mobile (`mobile/`, `npm audit`)

- **4 moderate** — `postcss < 8.5.10` ([GHSA-qx2v-qp2m-jg93](https://github.com/advisories/GHSA-qx2v-qp2m-jg93), XSS via unescaped `</style>` in CSS output).
- Path: transitively pulled by `expo` → `@expo/cli` → `@expo/metro-config` → `postcss`.
- Reachability: the vulnerable code path is in dev build tooling, not the runtime bundle shipped to devices. End-user impact is **low**.
- Fix requires bumping Expo SDK (breaking change). Tracked separately.

CI runs `composer audit --abandoned=ignore` on every push and will fail on new vulnerabilities.

---

## Defense in Depth

### Authentication

- **2FA** — email OTP (6 digit) with optional **trust-device** cookie (UUID + secret hashed, 30 days). Verify endpoint rate-limited 5/min.
- **Passkey (WebAuthn)** — via `laragear/webauthn`, FIDO2-compliant. Login flow is challenge-bound.
- **Social OAuth** — Google, Facebook, GitHub via Socialite. Callback explicitly refuses identity-overwrite when an email is already linked to a different provider id.
- **Captcha** — Google reCAPTCHA v2/v3 toggleable per environment.

### Authorization

- Spatie `permission`/`role` system with `active-permission` gate — a permission can be disabled centrally without revoking it from each role.
- **Granular tab permissions** — 85 named permissions covering every settings tab in Global Settings and Mobile Settings. `CheckTabPermission` middleware enforces access; `@cantab`/`@managetab` Blade directives available for views.
- **Impersonation** guarded against: self-impersonate, Developer role, inactive users, and nested loop. Tracked in `Cache` for the target user awareness banner and audit logged via `ImpersonationStatusChanged` event.

### Network & Boundary

- **IP access control** — `IpAccessControl` middleware with:
  - Global blacklist
  - Admin route whitelist (`/users*`, `/roles*`, `/permissions*`, `/system-config*`, `/backups*`, `/admin/*`)
  - Auto-block IPs that exceed configurable burst threshold (24h cooldown). Sends Telegram firewall alert.
  - HSTS toggle (HTTPS only).
- **Security headers** — `SecurityHeaders` middleware sets `X-Content-Type-Options: nosniff`, `X-Frame-Options: SAMEORIGIN`, `Referrer-Policy: strict-origin-when-cross-origin`, `Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()`, `X-XSS-Protection`, and (when HTTPS + opt-in) `Strict-Transport-Security: max-age=31536000; includeSubDomains; preload`.
- **Rate limit** — Per-endpoint throttle: `/login` (5/min), `/2fa verify` (5/min), `/forgot-password`, `/api/v1/login` (10/min), `/api/v1/register` (5/min), `/api/v1/otp/send` (5/min), `/api/v1/otp/verify` (10/min). Per-IP buckets isolated.
- **Single-session enforcement** — optional; logs out previous device when user logs in elsewhere.

### Passwords & Sessions

- **Bcrypt 12 rounds** in production (4 in test for speed).
- **Password policy** (`App\Services\Auth\PasswordPolicyService`): min/max length, mixed-case, digit, symbol, expiry, history reuse blocker (configurable N).
- **Password history** stored hashed in `password_histories`; reuse of last N raises validation error.
- **Sessions** stored in Redis. Admins can revoke sessions per user from `/system-settings/session-manager`.

### Data Integrity

- **Foreign keys** — all audit (`created_by`/`updated_by`) → `users(id) ON DELETE SET NULL`. Owned data (`password_histories`, `user_consents`, `user_trusted_devices`, `model_has_*`, `role_has_permissions`) → `ON DELETE CASCADE`. Cascade behavior is locked in by `tests/Feature/Database/CascadeIntegrityTest.php`.
- **Composite indexes** on hot lookups (`password_histories(user_id, created_at)`, `system_setting_revisions(key, created_at)`, `notifications(notifiable, read_at)`).
- **Soft deletes** — User, Role, Permission. Restore + force-delete flows tested.

### Data Retention

Semua data time-sensitive memiliki kebijakan retensi otomatis yang dijalankan oleh scheduler harian:

| Tabel | Retensi | Mekanisme |
|-------|---------|-----------|
| `otp_codes` | Setelah expired | `OtpCode::prunable()` — `expires_at < now()` |
| `user_trusted_devices` | Setelah expired | `UserTrustedDevice::prunable()` — `expires_at < now()` |
| `ai_healing_logs` | 90 hari | `AiHealingLog::prunable()` — `created_at` |
| `password_histories` | 365 hari | `PasswordHistory::prunable()` — `created_at` |
| `mobile_error_logs` | 90 hari | `MobileErrorLog::prunable()` — `occurred_at` |
| `ai_usage_logs` | 90 hari | `AiUsageLog::prunable()` — `created_at` |
| `mobile_sync_logs` | 30 hari | `MobileSyncLog::prunable()` — `synced_at` |
| `notifications` | 30 hari | `Notification::prunable()` — `created_at` |
| `activity_log` | 365 hari | `activitylog:clean` via Spatie config |
| `telescope_entries` | 48 jam | `telescope:prune --hours=48` |
| `dashboard_widget_preferences` | Dihapus saat user dihapus | FK `ON DELETE CASCADE` ke `users` |

Scheduler berjalan: `model:prune` pukul 03:00, `telescope:prune` pukul 03:05, `activitylog:clean` harian. Sesuai prinsip **data minimization** UU PDP No. 27/2022.

### Audit & Forensics

- **Spatie ActivityLog** on User, Role, Permission, SystemSetting.
- **System config revisions** — separate `system_setting_revisions` table captures actor, IP, user agent on every change.
- **`ActivityFormatter`** redacts sensitive keys (`password`, `remember_token`, `secret`, `key`, `token`, `2fa_secret`) from displayed diffs.

### Error Handling & Monitoring

- **Custom exception classes** — `App\Exceptions\{SystemConfig,BackupOperation,Monitoring}Exception` with factory methods, allowing specific handlers rather than generic `\Exception` catches.
- **Sentry** — production error reporting; sample rates set in `.env`.
- **Health endpoint** — `GET /api/health` reports DB, Redis, storage, queue; returns `503` only when any check `fail`s, `200` for `warn` (e.g. disk >90%).

---

## Quality Gate

| Check | Tool | Threshold |
|-------|------|-----------|
| Unit + feature tests | Pest 4 | All passing |
| Static analysis | Larastan level 5 + baseline | No new errors |
| Code style | Laravel Pint | All files PSR-12 compliant |
| Dependency audit | `composer audit` | 0 vulnerabilities |
| N+1 regression | Pest (Query Log) | Bounded query count |

CI workflow: `.github/workflows/ci.yml`.

---

## Disclosure Timeline (template)

```
T+0       Report received
T+48h     Acknowledgement sent
T+7d      Patch landed (critical) / ETA shared (others)
T+30d     Coordinated disclosure window ends
```
