# Security Practices — Kordant Android > **Last updated:** 2026-06-01 > **Package:** `com.kordant.android` > **Purpose:** Document security practices for Play Store Data Safety form and user transparency --- ## 1. Encryption in Transit ### TLS Configuration All network communication between the Kordant Android app and backend servers is encrypted using **TLS 1.2 or higher**. **Implementation:** - `network_security_config.xml` enforces `cleartextTrafficPermitted="false"` for all domains - Debug builds allow cleartext for local development via `` - API base URL uses HTTPS (`https://api.kordant.com`) ### Certificate Pinning The Android app implements **SHA-256 certificate pinning** for production and staging domains: | Domain | Pin 1 (Primary) | Pin 2 (Backup) | |--------|----------------|----------------| | `api.kordant.com` | Primary SHA-256 hash | Backup SHA-256 hash | | `staging.api.kordant.com` | Staging SHA-256 hash | Staging backup SHA-256 hash | **File:** `res/xml/network_security_config.xml` **Rotation:** Pins include a backup for graceful certificate rotation. Update pins before certificate expiry. Expiration set to 2027-06-01. ### TLS Enforcement Points | Component | Enforcement | |-----------|------------| | OkHttpClient | HTTPS URLs only (BuildConfig.API_BASE_URL) | | AUTH interceptor | All auth requests via HTTPS | | API service | Retrofit base URL uses HTTPS | | Image loading | Coil via OkHttp with TLS | --- ## 2. Encryption at Rest ### EncryptedSharedPreferences All sensitive data is stored in **EncryptedSharedPreferences** using: | Property | Value | |----------|-------| | **Key encryption** | AES256-SIV (deterministic, allows key lookup) | | **Value encryption** | AES256-GCM (authenticated encryption) | | **Master key** | Android Keystore (`MasterKey.Builder` with `KeyScheme.AES256_GCM`) | | **Library** | `androidx.security:security-crypto` | ### Data Stored Encrypted | Data | Key | File | |------|-----|------| | Access token | `access_token` | `SecureStorageManager.kt` | | Refresh token | `refresh_token` | `SecureStorageManager.kt` | | User profile (PII) | `user_profile_json` | `SecureStorageManager.kt` | | FCM device token | `fcm_device_token` | `SecureStorageManager.kt` | | Biometric preference | `biometric_enabled` | `SecureStorageManager.kt` | ### Non-Sensitive Data (Unencrypted) User preferences that do not contain PII are stored in Android's standard **Preferences DataStore**: - Theme selection (system/light/dark) - Language/locale - Notification preferences (alerts/marketing/system toggles) - Onboarding completion status - App version for migration tracking - Background sync toggle - Last sync timestamp ### Spam Database (Hashed) Phone numbers in the local SQLite spam database are **SHA-256 hashed** before storage. | Field | Storage | |-------|---------| | `number_hash` | SHA-256 hash of normalized phone number | | `pattern` | Wildcard pattern (e.g., `+1-800-*`) | | `action` | `block`, `flag`, `allow` | | `category` | `scam`, `telemarketer`, `robocall`, `spam` | | `spam_score` | 0-100 confidence score | Raw phone numbers are **never written to disk** in the spam database. --- ## 3. Secure Deletion ### Overwrite-Then-Remove The app implements **secure deletion** for sensitive keys to mitigate forensic recovery: ``` secureOverwriteAndRemove(key) { for (i in 0 until 3) { overwrite with random data → apply() } remove(key) → apply() } ``` ### Deletion Methods | Method | What It Clears | Use Case | |--------|---------------|----------| | `clearAllAuthData()` | Access token, refresh token, user profile | Logout | | `clearAllData()` | All encrypted preferences including biometric | Account deletion (GDPR) | | `clearAll()` (DataStore) | All user preferences | Reset to defaults | | `clearAll()` (CacheManager) | API response cache | Logout / cache clear | | `clearAll()` (SpamDatabase) | Spam numbers + call logs | Full resync / account deletion | --- ## 4. Root Detection & Anti-Tampering ### Detection Methods | Check | Detection Target | |-------|-----------------| | SU binary paths | `/system/bin/su`, `/system/xbin/su`, `/data/local/su`, etc. | | Busybox paths | `/system/xbin/busybox`, `/data/local/bin/busybox` | | Dangerous props | `ro.debuggable=1`, `ro.secure=0` | | Build tags | `test-keys`, `dev-keys` | | Magisk indicators | `/sbin/.magisk`, `/data/adb/magisk`, Magisk packages | | Root management packages | Magisk, SuperSU, KingRoot, LuckyPatcher, etc. | | SU command execution | `su -c id` — checks if uid=0 | | App signature verification | SHA-256 hash of signing certificate | | Debugger detection | `android.os.Debug.isDebuggerConnected()` | | ADB over network | `service.adb.tcp.port` system property | | Emulator detection | Known properties, model, manufacturer, fingerprint | | Installer source verification | Play Store, Amazon App Store, Samsung Galaxy Store | ### Response to Detection | Detection | Behavior | |-----------|----------| | Root detected | Features degraded; reported to backend and Crashlytics | | Tampering detected | Biometric and payment features disabled | | Emulator detected | Features may be restricted | | Untrusted install | Warning logged, security restrictions applied | --- ## 5. Log Sanitization All network logs are sanitized before writing to prevent PII exposure: | Pattern | Redacted To | |---------|-------------| | `Bearer ` | `Bearer [REDACTED]` | | `\b\d{10,15}\b` (phone numbers) | `[PHONE_REDACTED]` | | Email addresses | `[EMAIL_REDACTED]` | | Refresh tokens in bodies | `"refreshToken":"[REDACTED]"` | | Access tokens in bodies | `"accessToken":"[REDACTED]"` | | ID tokens in bodies | `"idToken":"[REDACTED]"` | | Passwords in bodies | `"password":"[REDACTED]"` | **Implementation:** `NetworkModule.kt` → `provideLoggingInterceptor()` **Log levels:** - **Debug builds:** Full headers + sanitized bodies - **Release builds:** Headers only (no body logging) --- ## 6. Token Refresh Security ### Automatic Silent Refresh | Property | Value | |----------|-------| | **Trigger** | HTTP 401 Unauthorized | | **Mechanism** | `AuthInterceptor.intercept()` → `refreshAccessToken()` | | **Concurrency** | Synchronized via `refreshLock` to prevent race conditions | | **Fallback** | Clears tokens on refresh failure → user re-authenticates | ### Token Storage | Token | Storage | Encryption | |-------|---------|------------| | Access token | EncryptedSharedPreferences | AES256-GCM | | Refresh token | EncryptedSharedPreferences | AES256-GCM | --- ## 7. Network Security ### OkHttp Configuration | Property | Value | |----------|-------| | Connect timeout | 30 seconds | | Read timeout | 30 seconds | | Write timeout | 30 seconds | | TLS enforcement | Platform default (TLS 1.2+) | | Certificate pinning | SHA-256 pins for api.kordant.com | ### Retrofit API Configuration | Property | Value | |----------|-------| | Base URL | `https://api.kordant.com/` (production) | | Converter | Kotlinx Serialization JSON | | Headers | `X-Request-ID`, `X-Client-Version`, `X-Client-Platform` | --- ## 8. Biometric Authentication | Property | Value | |----------|-------| | **Library** | `androidx.biometric:biometric` | | **Storage** | Preference flag in EncryptedSharedPreferences | | **Root check** | Biometric disabled on rooted/tampered devices | | **Fallback** | Device credentials (PIN/pattern/password) | --- ## 9. Data Collection Compliance ### Data Minimization The app collects only the data necessary for its core functionality: | Feature | Minimum Data Required | |---------|----------------------| | Authentication | Email, password (or Google account ID), name | | Call Screening | Incoming phone number (temporary, hashed for storage) | | VoicePrint | Voice recording samples | | DarkWatch | Watchlist items (email, phone, name to monitor) | | Analytics | Device info, app version (no personal identifiers) | | Crash reporting | Crash stack trace, device model, OS version | ### User Consent | Data Type | Consent Mechanism | |-----------|------------------| | Account creation | Explicit signup form | | Google Sign-In | OAuth consent screen | | Voice recordings | `RECORD_AUDIO` permission + in-app rationale | | Call screening | `READ_PHONE_STATE` permission + in-app rationale | | Notifications | `POST_NOTIFICATIONS` (Android 13+) + in-app toggles | | Crash reporting | Crashlytics opt-out (configured in manifest) | | Marketing communications | Explicit opt-in via notification settings | --- ## 10. Independent Security Review **Status:** ⚠️ Pending An independent third-party security audit is planned before the production launch. The audit will cover: - Penetration testing of the mobile application - API security assessment - Cryptographic implementation review - Privacy compliance review --- ## 11. Compliance Standards | Standard | Status | Notes | |----------|--------|-------| | **GDPR** | ✅ Compliant | Data deletion, portability, consent, breach notification | | **CCPA** | ✅ Compliant | Right to know, delete, opt-out, non-discrimination | | **COPPA** | ✅ Compliant | No children under 13 data collection | | **Play Store Data Safety** | ✅ Complete | All data types accurately declared | | **Android Target API 36** | ✅ Compliant | No deprecated API usage | | **TLS 1.2/1.3** | ✅ Enforced | Cleartext traffic blocked | | **OWASP MASVS** | ⚠️ Partial | Security audit planned for full certification |