**Memo: Security/Compliance Questionnaire — Evidence Review**
**To:** Aylin Demir | **From:** Claire Dubois | **Fri 2026-01-09**

**1. Access control (#1) — mostly sound, with one real gap.**
548 of 550 staff (merchant-admin) users are active, 2 deactivated, 0 suspended/invited (*Staff access currency*, Mon). Access looks tiered, not flat: baseline categories (catalog 99.3%, orders 95.3%, customers 92.0%, support 87.1%) are near-universal, while sensitive categories (billing 45.3%, compliance 44.6%, settings 44.6%, crm 45.1%) sit around 45-53% — consistent with ~1.02 roles/user, i.e. most staff get one broad role, a subset also gets a second, stronger one (*Elevated access by category*, Tue). The 2 deactivated accounts still hold the baseline categories but **none** of the sensitive ones — reassuring, though not a full revocation.

**The gap:** I swept all 13 identity/access tables (roles, user_roles, role_permissions, permissions, api_keys, invitations, mfa_devices, sessions, teams, service_accounts, PATs) against audit_log + audit_log_archive for all 36 months. Only `users` shows any activity (login/logout/update/delete/export) — **zero logged events, ever, for any role or permission grant/revocation** (*Audit log coverage for identity tables*, Wed). We can show today's access snapshot but **cannot currently evidence who granted or revoked access, or when.** I'd flag this plainly rather than paper over it.

**2. DSAR handling (#3) — healthy, one loose end unresolved.**
~48 requests over 3 years, 43 completed, SLA window is a consistent 30 days, on-time completion mostly 100%/month (*DSAR volume & timeliness*, Mon). The 5 cases that looked "open and overdue for years" turned out to be 3 rejected erasure requests (oldest 2023-05-26) that were decided but never got a `completed_at` stamped — a records gap, not a live breach (*DSAR backlog reconciliation*, Tue). I tried twice to recover the actual rejection date from change_history/audit_log; **both attempts failed** with the same JSON-casting error, which persisted even after I excluded cross-table id collisions — this looks like an engine/type-inference issue on `change_history.after_data`, not a logic bug I can fix from the report side. **I cannot confirm these 3 rejections were decided within the due date.**

**3. Login security (#2) — partial coverage, one anomaly worth a look.**
54.9% of active staff have confirmed MFA (57.8% any device); customers show 0% (*MFA adoption*, Wed) — MFA appears staff-only today. Failed-login rate is a steady ~6%/month except **February 2025: 60.8% failed (7,429/12,211), with 102 distinct emails hitting 5+ failures that month vs. 0-2 in every other month** (*Failed logins & suspicious access*, Thu). Audit `access_denied` events that month were only 6 — in line with baseline — so **this 10x anomaly did not trigger any visible rise in flagged suspicious access.** Worth an incident lookback before we cite this month's data anywhere.

**4. Retention (#4, bonus).** Only `audit_log` has a configured retention policy — 730 days, 100% of tenants, 100% active, 92.5% run in last 90 days (*Retention policy coverage*, Thu). `access_log`, `change_history`, `data_subject_requests`, `compliance_events`, `login_attempts` have **no retention policy at all** — unconfirmed how long that data is kept.

**Confidence:** DSAR volume/timeliness and the two-tier access model, solid. MFA baseline and the Feb-2025 anomaly, solid numbers. **Open/untrustworthy:** the 2 failed JSON queries (no data), the role/permission audit gap (needs an engineering fix, not a report), and retention for everything but audit_log.

**Next steps:** (1) escalate the Feb 2025 login spike for incident review; (2) ask engineering to inspect `change_history.after_data` directly to recover the 3 rejection dates; (3) raise role/permission-change logging as a product gap; (4) scope retention policies for the other five tables; (5) pick up #5 (incidents) next week as agreed.