UNDA — Threat Model
Status: Draft. Attacker categories and mitigations for the prototype scope. Update when introducing cloud sync, OAuth integrations, or any admin tooling.
Assets
| Asset | Sensitivity | Where it lives |
|---|---|---|
| Cycle log (dates, symptoms, phase inferences) | SENSITIVE_HEALTH | unda.db on user device |
| Workout sessions with phase snapshot + felt-score | FITNESS + SENSITIVE_HEALTH | unda.db on user device |
| Profile (level, sports, equipment) | FITNESS | unda.db on user device |
| OAuth tokens (Strava/Intervals/Garmin — planned) | HIGH secrets | flutter_secure_storage (Keychain / EncryptedSharedPrefs) |
| Supabase session token (when cloud sync on — planned) | HIGH secrets | Supabase SDK secure storage |
Attackers considered
A1. Device thief / opportunistic finder
- Vector: Device is stolen unlocked, or lock is bypassed.
- Impact: Read/write attempt against
unda.db. - Mitigations (shipped):
- SQLCipher AES-256 encryption at rest (via
sqflite_sqlcipher). The DB file is ciphertext on disk. - Key stored in the OS secure store — Keychain on iOS (
KeychainAccessibility.first_unlock), EncryptedSharedPreferences on Android — viaflutter_secure_storage. Never in source, logs, or exports. - Device OS lock still the outer defence: Keychain items with
first_unlockaccessibility require the device to have been unlocked at least once since boot.
- SQLCipher AES-256 encryption at rest (via
A2. Backup/exfiltration attacker (unencrypted backups)
- Vector: iCloud/Google backup includes the sqflite database.
- Impact: Backups readable by the platform account holder or an attacker with access to their credentials.
- Mitigations:
- Mark the DB file as "no backup" until SQLCipher lands (planned entry — currently not applied).
- Encourage account MFA (documentation in Privacy Notice).
A3. Local malicious app (Android)
- Vector: Another app on the same device attempts to read UNDA's storage.
- Impact: Would need to escalate to app-private storage, which Android sandboxes.
- Mitigations: Standard Android sandbox. Do not use
getExternalFilesDir()or world-readable storage. Confirmed: sqflite usesgetApplicationDocumentsDirectory().
A4. Cloud-sync interception (planned)
- Vector: Network attacker on hostile Wi-Fi or MITM.
- Impact: Read/modify cycle data in flight.
- Mitigations: TLS 1.2+ mandatory (Supabase enforces this). Certificate pinning is out of scope for v1 but a candidate for later.
A5. Supabase administrator or breach (planned)
- Vector: Row-level compromise via Supabase incident.
- Impact: Health data readable across many users.
- Mitigations:
- RLS policies enforced on every table (§7.2).
- EU-region project.
- Backups encrypted at rest.
- No PII in Supabase logs.
- Least-privilege service roles.
A6. Third-party integration provider (planned)
- Vector: Strava/Intervals/Garmin token compromise.
- Impact: Attacker reads user's fitness history; may correlate with UNDA account.
- Mitigations:
- Tokens in
flutter_secure_storage, never in DB or logs. - Scopes limited to what a feature needs (§8.1).
- Immediate revoke on disconnect + prompt user to revoke provider-side.
- Tokens in
A7. Malicious PR / dependency
- Vector: Compromised dependency injects analytics/exfil code.
- Impact: Cycle data leaves the device silently.
- Mitigations:
- Pinned versions in
pubspec.yaml. - Dependency scanning (planned:
dart pub outdated --mode=security, Dependabot). - PR review with the compliance checklist (§22).
- Pinned versions in
A8. Legal compulsion / subpoena
- Vector: Government or civil demand for cycle data.
- Impact: Especially sensitive given the current global environment around reproductive health.
- Mitigations:
- Local-first by default → in most cases UNDA has nothing to hand over.
- When cloud sync is on: SCC/DPA + data-minimisation reduce, but do not eliminate, the exposure.
- Retention policy (§13) minimises what exists at any moment.
- Never link email/name to cycle data outside the encrypted sync path.
Explicitly out of scope for v1
- Cloud sync (not yet wired) — separate threat-model update required when it lands.
- Wearable OAuth flows — same.
- Admin dashboard / support tooling — not built.
- Web app.
Review triggers
Redo this document when:
- Any new datastore is added.
- Cloud sync launches.
- A new integration is wired.
- Any authenticated admin surface is added.
- A vulnerability report identifies a gap not covered here.