7.0 KiB
7.0 KiB
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/webauthnis 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, 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/rolesystem withactive-permissiongate — 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.
CheckTabPermissionmiddleware enforces access;@cantab/@managetabBlade directives available for views. - Impersonation guarded against: self-impersonate, Developer role, inactive users, and nested loop. Tracked in
Cachefor the target user awareness banner and audit logged viaImpersonationStatusChangedevent.
Network & Boundary
- IP access control —
IpAccessControlmiddleware 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 —
SecurityHeadersmiddleware setsX-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 bytests/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_revisionstable captures actor, IP, user agent on every change. ActivityFormatterredacts sensitive keys (password,remember_token,secret,key,token,2fa_secret) from displayed diffs.
Error Handling & Monitoring
- Custom exception classes —
App\Exceptions\{SystemConfig,BackupOperation,Monitoring}Exceptionwith factory methods, allowing specific handlers rather than generic\Exceptioncatches. - Sentry — production error reporting; sample rates set in
.env. - Health endpoint —
GET /api/healthreports DB, Redis, storage, queue; returns503only when any checkfails,200forwarn(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