If you believe you've found a security issue in Notes Tech, please do not open a public GitHub issue. Instead, email :
Subject : [SECURITY] Notes Tech — <short summary>
Include :
- A description of the issue and its potential impact.
- Steps to reproduce (or a proof-of-concept).
- Affected version (Réglages → À propos → Notes Tech vX.Y.Z).
- Your contact for follow-up.
You'll get an acknowledgement within 72 hours. A coordinated disclosure timeline will be agreed upon if the issue is confirmed.
- Notes Tech app code (
lib/,android/) - Module sibling
files_tech_voiceif relevant - Crypto implementations (SQLCipher integration, KEK derivation / storage, panic mode irreversibility)
- Permission handling (
RECORD_AUDIO) - File handling / SAF imports / path traversal
- Dependency vulnerabilities surfaced by
health_check.sh
- Issues in third-party packages (file an issue upstream).
- Issues requiring a rooted device or pre-existing malware on the device.
- Social engineering against the user.
- Denial of service via deliberately oversized notes / payloads.
Notes Tech is designed for individuals and professionals who want local-only notes with strong cryptographic guarantees. Three adversary classes are considered :
- Confidentiality at rest : SQLCipher (AES-256) for the database, AES-256-GCM for per-folder vault notes. KEK sealed by Android Keystore (hardware-backed on modern devices).
- Per-folder vault adds a second factor (passphrase or PIN) on top of the device lockscreen.
- Panic mode : a confirmed delete-everything action that runs a deterministic ordered sequence (see below). Designed to be fast and irrecoverable under coercion.
- PIN auto-wipe : 5 failed PIN attempts on a vault wipes that vault's keys atomically (with crash-resume via prefs flag).
setUserAuthenticationRequired(false)on PIN Keystore keys : the PIN is the sole factor — adding biometric would expose the user to forced fingerprint unlock (a biometric-derived key survives reboot).
- No
INTERNETpermission means a compromised dependency cannot exfiltrate notes via the standard network path. Data exfiltration through standard channels is technically impossible without re-installing a modified APK. - No
FOREGROUND_SERVICE, noPOST_NOTIFICATIONS, noRECEIVE_BOOT_COMPLETED— minimal attack surface. FLAG_SECUREblocks Recents previews and screen recording.allowBackup=false+dataExtractionRulesblock Smart Switch / Android Backup exfiltration.
- Argon2id RFC 9106 for passphrase derivation :
m=64 MiB, t=3, p=1, 32-byte output(vault default). PIN mode uses lighter parametersm=32 MiB, t=2because the device-bound Keystore wrap is the primary defense and on-device rate-limiting prevents brute force. - AES-256-GCM for note content with AAD =
note_id(prevents ciphertext substitution between notes). - KEK wrap with AAD =
folder_id(prevents wrap reuse across folders). - HMAC verifier in constant time to detect bad passphrase / PIN without trial-decrypting every note.
- SQLCipher 4 (AES-256-CBC + HMAC-SHA512), key sealed via
flutter_secure_storage→EncryptedSharedPreferences→ Keystore.
The panic sequence is deterministic and best-effort (a step that throws does not abort the next ones) :
FLAG_SECUREforced ON, microphone capture stoppedfoldersLockAll— lock every open vault, wipe folderKek from RAMpinKeysWipe—deleteKeysWithPrefix("vault_pin_")(Kotlin)kekDestroy— destroy the master Keystore key (DB instantly unreadable)- Background workers paused (coordinator / indexing / backlinks)
dbWipe— overwrite SQLCipher header (16 MiB cap) + delete.db,.db-wal,.db-shm- Whisper / Gemma model files deleted, all prefs cleared, tmp purged
- Forensic recovery from a physical memory dump of an unlocked, rooted device is partially possible (Dart heap GC eventually recycles strings, but a snapshot during use can leak plaintext).
- A determined nation-state attacker with custom kernel exploits is out of scope.
- Display privacy (
FLAG_SECURE) is on by default but opt-out is possible in Settings.
We follow a 90-day disclosure window by default :
- Day 0 : your report received.
- Day 0-7 : initial triage, severity assigned.
- Day 7-60 : fix developed, tested, audited.
- Day 60-90 : release with patched version, public CVE if applicable.
- Day 90+ : you're free to publish your write-up.
Critical issues (RCE, key extraction, full data exfiltration) may be patched faster than 90 days.
Each release is checked via :
flutter analyze(lints stricts)flutter testbash j:\applications\health_check.sh notes_tech:- OSV-Scanner (CVE in dependencies)
- gitleaks (secrets in git history)
- Manifest hardening (no
debuggable, nocleartextTraffic, no excessive permissions) - Signing config (R8 enabled, no debug fallback for release)
- FileProvider (no
<root-path>, no global app-private exposure) - Crypto patterns (no MD5/SHA-1 for security, PBKDF2 ≥ 100k iter)
- Kotlin patterns (
canonicalFile,FLAG_IMMUTABLEPendingIntent)
- 4-agent audit (architecture / security / performance / coherence) for material features.
Code source : https://github.com/gitubpatrice/notes_tech Licence : Apache License 2.0
- Wipe DB header plafonné à 16 Mo : la
kekDestroyprécédente garantit déjà le secret cryptographique (la base entière devient illisible sans la clé Keystore détruite). Écraser le fichier complet n'apporte rien sur eMMC / UFS moderne avec wear-leveling : les blocs physiques ne correspondent plus aux blocs logiques. 16 Mo suffisent pour neutraliser le header SQLCipher et un préfixe raisonnable. Bénéfice marginal vs latence du panic mode → 16 Mo. setUserAuthenticationRequired(false)sur les clés Keystore PIN (ajouté en v0.9.4) : le PIN applicatif est l'unique facteur d'authentification du coffre. Le doubler par une exigence biométrique exposerait l'utilisateur à la contrainte physique (un attaquant peut forcer un doigt sur le capteur, et une clé dérivée biométrique survit au reboot). Le PIN seul, combiné au scellage Keystore device-bound et à l'auto-wipe à 5 essais, offre un meilleur compromis pour le modèle de menace « contrainte ».- AAD =
folder_id/note_id: empêche un attaquant local d'extraire un blob chiffré et de le rejouer dans le contexte d'un autre dossier ou d'une autre note (aucune confusion possible entre contextes cryptographiques distincts). - Reindex backlinks différé 2 s (v0.9.3) : évite le coût quadratique sur saisie active, tout en garantissant la cohérence de l'index avant toute fermeture / lock du coffre.