Rendered from the current local source. Published APKs and GitHub may differ.
Decryptum threat model
Current development source reviewed 2026-10-07. Scope: Android app, its local storage and integrations, optional debug advisor, manual exports and the static presentation site. This is an engineering model of risks and controls, not a completed vulnerability audit or evidence that scenarios were exploited.
Overview
Decryptum is a local-first Android vault/TOTP/generator with Autofill and Android 14+ Credential Provider entry points. Compose ViewModels/use cases read repositories backed by Room/SQLCipher. The field DEK is unlocked by a master-password-derived key or a supported biometric cipher. A separate Keystore-wrapped key opens the database. The local analyzer sees unlocked password models and produces local references/counts. The advisor receives a four-integer DTO, not vault objects. There is no hosted vault or sync backend.
| Component | Source (under app/src/main/java/com/doffi4/doffisecure/) |
Role |
|---|---|---|
| Startup/storage | DecryptumApplication.kt, di/AppModule.kt, data/local/database/ |
Native library, DI, database open/migration |
| Key/lock control | security/PasswordCrypto.kt, DatabaseKeyManager.kt, AppLockManager.kt |
Distinct DB and field keys, unlock and lifetime |
| Vault repositories | data/repository/PasswordRepositoryImpl.kt, PasskeyRepositoryImpl.kt |
Read/write and secret decryption |
| External entry points | autofill/, manifest |
Framework binding, chooser/auth/save/assertion activities |
| Passkey crypto | security/webauthn/WebAuthnCryptoEngine.kt |
Software P-256 key generation and WebAuthn structures |
| Export/import | security/CsvManager.kt, ui/password/SettingsViewModel.kt |
Document-provider data transfer |
| Local analysis | domain/security/, ui/security/ |
Local heuristics and lifecycle-cleared findings |
| Remote advisor | domain/advisor/, data/advisor/, debug/release factories |
Allowlist, consent, fixed HTTPS transport; release disabled |
| Other exposure | security/FaviconFetcher.kt, SecureClipboard.kt, MainActivity.kt |
Icon networking/cache, clipboard and screen policy |
Effective resources and independently enforced boundaries:
| Workflow | Resource/capability | Configuration/precedence | Effective location/value | Readers/writers/recipients | Control / uncertainty |
|---|---|---|---|---|---|
| Database open | Random 32-byte SQLCipher key | DatabaseKeyManager; independent of master password |
Wrapped blob/IV in private prefs; process cache | App/Keystore/SQLCipher | AES-GCM Keystore wrapper without user-auth requirement; root/app-process compromise exceeds sandbox |
| Modern vault unlock | 256-bit field DEK | Master Argon2id wrapper or biometric RSA-OAEP wrapper | Wrapped prefs; unwrapped key in RAM | Authorized app flow | Biometric CryptoObject in main flow; integration variants need fresh-auth verification |
| Passkey sign/export | Software private key | WebAuthn engine → DEK encryption → repository | Encrypted PKCS8 in DB; may be readable in CSV | App, selected RP/app, chosen export destination | Software/exportable; caller/origin binding and protocol interoperability unverified |
| Debug advisor | One aggregate request | Debug factory reads runtime private file only after consent | files/claude-advisor.properties; fixed https://api.anthropic.com/v1/messages |
Anthropic; caller holds developer key | Four-Int DTO, explicit writer, no redirects/retries, bounded/cancellable response |
| Release advisor | No remote capability | Release factory constructs disabled service | No config read or remote call | None through this feature | Release gate unit test; deployment/provider enablement would change model |
| Icons | Domain fetch/cache | Caller enabled; setting not propagated everywhere |
Google → DuckDuckGo → direct/apex; local caches | Providers, sites, possible redirect recipients | HTTPS; metadata disclosure persists; no comprehensive network-off control |
| HIBP | Retained range-query transport | Current UI/ViewModel no longer invokes it | Five-hex SHA-1 prefix if reconnected | HIBP | Current center not checked; validation/consent/coverage gate before reconnection |
| Manual export | Unencrypted credential file | User-selected SAF URI | Local or cloud-backed document provider | User/provider/any file reader | No independent encryption; success does not prove complete restore |
| Landing site | Static HTML/CSS/assets | Empty site URL = noindex preview; Pages workflow sets the public origin | website/dist |
Browser/GitHub Pages; GitHub on navigation | No analytics/backend/remote fonts; theme localStorage only; host logging unknown |
Assets, trust boundaries and assumptions
Protect vault passwords, account identities, TOTP seeds, private passkeys, DB/DEK/wrapping material, integrity of records/migrations, and exported copies. Availability and recoverability matter alongside confidentiality. A leaked TOTP seed/private passkey is not fixed by clearing an expired displayed code.
Trust boundaries include: device/OS sandbox ↔ app-private files; master/biometric authorization ↔ DEK access; locked ↔ unlocked session and every framework entry point; caller app/site ↔ selected credential; database ↔ import/export/document provider; decrypted source models ↔ local findings ↔ sanitized advisor DTO; network ↔ untrusted responses; maintained source ↔ signed APK/website artifact.
Expected invariants: secrets require current authorization, lock/stop clears sensitive session state, corrupted encrypted input fails visibly, migration never discards the last usable source, credential recipients are validated, network consent/payload matches user disclosure, AI cannot read identities/secrets or mutate the vault, and release artifacts match reviewed source/signing identity. These are goals; existing controls do not establish all of them.
Assume ordinary Android sandbox and Keystore behavior for the baseline attacker. A malicious local app initially lacks the app UID/private filesystem and must use exposed framework/user-authorized surfaces. A filesystem thief does not automatically have live Keystore execution. Root/OS and injected unlocked-process attackers have stronger capabilities and can observe keys/plaintext. A remote provider initially sees only data actually sent; no remote vault-read endpoint is implemented. A network attacker can deny service and observe metadata, but HTTPS limits ordinary transport tampering absent compromised trust/configuration.
No tenant/admin/hosted account model exists. No claim of universally hardware-backed keys, guaranteed zeroization, encrypted portable recovery, proven WebAuthn compliance, independent audit or complete network isolation is made. Historical legacy formats/native migration, actual hardware properties, OEM behavior, accessibility, device/browser compatibility and full restore need verification. SECURITY.md lists known gaps; none is a blanket accepted-risk exclusion.
Attacker stories and mitigations
Priorities below guide investigation, not confirmed vulnerability severity. Source anchors refer to the implementation; native validation remains incomplete.
| Priority | Scenario and capability gain | Prerequisites / impact | Existing controls | Required mitigation/evidence | Source |
|---|---|---|---|---|---|
| Critical gate | Migration failure loses the last usable vault | Legacy plaintext DB; failed conversion or interrupted replacement; availability loss | Source preserved until validated atomic replacement; WAL/schema/export checks | Native crash/low-space/upgrade and rollback fixtures | data/local/database/DatabaseMigrator.kt |
| High | Stolen locked phone leaks secret material | File access or bypassed integration authorization; account takeover | DB encryption, modern DEK wrapper, guarded password reads, lock | Verify every auth entry point and legacy path, rate limits and snapshot cleanup; OS lock remains essential | PasswordCrypto, DatabaseKeyManager, repositories, autofill/ |
| High | Stolen unlocked phone enables copying/export/signing | App already unlocked; user authority is available | Auto-lock timing and optional integration auth | Minimize unlocked exposure and test fresh-auth/export paths; do not promise protection after authorized unlock | AppLockManager, SettingsViewModel, auth activities |
| High | Malicious local app receives the wrong credential | Framework selection, heuristic recipient match or incorrect caller/origin binding | Bind permissions, non-exported helper activities, user selection | Validate package/certificate/origin/RP binding; adversarial device/browser tests; consider capability gate | Manifest, AutofillMatcher, provider/save/auth activities |
| High | Rooted/compromised OS reads active keys/plaintext | Privileged filesystem/process/input access | Encryption at rest reduces a narrower offline-file threat | Explicitly outside full protection guarantee; minimize plaintext lifetime, test ordinary boundaries separately | Key managers, repositories, UI |
| High | Filesystem theft exposes metadata or enables password attack | Copy of app files; Keystore availability varies | SQLCipher, wrapped field/DB keys | Verify device hardware/legacy behavior and KDF performance; inspect favicon caches/settings exposure | DatabaseKeyManager, PasswordCrypto, FaviconFetcher |
| High | Compromised export exposes all exported credentials | Reader of unencrypted SAF export/provider copy | User chooses destination | Prominent plaintext boundary; implement/test independent encrypted recovery later; verify complete round trip | CsvManager.export, encodePasskeyFields |
| Medium/High | Clipboard observer copies a secret before clearing | OS-permitted clipboard observation or compromised keyboard/accessibility | Sensitive flag and best-effort ~30s cleanup | Test OS/OEM behavior; avoid unnecessary copies; no guarantee against an observer | SecureClipboard, clipboard receivers |
| Medium/High | Screenshot/log observer obtains sensitive context | Other activities, diagnostic logs, accessibility or external camera | MainActivity default FLAG_SECURE | Shared sensitive-screen/log policy; redaction/release checks and real-device tests | MainActivity, autofill/, existing logs |
| Medium | Network attacker/provider learns service metadata or blocks requests | Icon resolution; HIBP only if reconnected; configured debug advisor | HTTPS, icon cache; advisor time/size limits | Complete caller consent/toggle propagation, strict parsing, traffic capture; no automatic reassuring success | FaviconFetcher, PwnedPasswordsRepository, advisor transport |
| Medium | Compromised remote AI gives malicious advice or attempts data extraction | Consented configured debug request | No vault dependency, four counts only, no tools/writes/clickable generated links, strict response shape, release disabled | Keep guidance untrusted/manual; transport/lifecycle tests; changing payload/auth model requires review | DTO, codec/service/controller/panel, release factory |
| High | Compromised build/distribution swaps an artifact | Dependency/build/signing or hosting access | Source/lockfile/wrapper hash; static build | Real release key, certificate continuity, checksums, reproducibility and reviewed provenance | app/build.gradle.kts, Gradle wrapper, website build |
Severity calibration
Critical: reachable loss of the only usable vault or unauthorized broad secret/key access. High: recipient-trust/auth bypass, leaked recovery/TOTP/passkey material, unrecoverable upgrades, or unsafe artifacts with concrete exposure. Medium: conditional metadata exposure, incomplete screen/clipboard policy, misleading error/coverage state or untrusted guidance with a plausible consequence. Low: narrowly scoped hardening with no established new privilege or sensitive asset loss.
An already-rooted attacker having privileged access is not itself a new app vulnerability, but reachable ordinary-privilege failures remain reportable. Unknown runtime behavior must stay unknown until tested; source tests alone do not certify AndroidKeyStore, native SQLCipher or framework caller trust.