Threat Model

April 28, 2026 · View on GitHub

What react-native-sensitive-info defends against

  • Casual filesystem access on a rooted/jailbroken device. Values are encrypted at rest with hardware-backed keys when the platform supports it; an attacker with shell access cannot recover plaintext without unlocking the master key.
  • Cold-storage exfiltration of app data. Keychain / Keystore entries are bound to the device and (when applicable) to a biometric or device passcode. Backups exclude protected entries.
  • Process-internal tampering. Each entry carries an HMAC-SHA256 integrityTag over its metadata + ciphertext. Reads validate the tag and surface IntegrityViolationError on mismatch.
  • Biometric re-enrollment / "stolen device" reset. Entries written with secureEnclaveBiometry or biometryCurrentSet are invalidated by the OS when the user enrolls or removes a biometric. Reads then surface KeyInvalidatedError, prompting the app to re-onboard.
  • Programmer error. TS-side validation (InvalidArgumentError) rejects empty keys, oversized values, and non-string inputs before any native call is made.

What it explicitly does not defend against

  • Compromised JavaScript runtime. If an attacker can run arbitrary JS in your app, they can call getItem directly. Use additional defense-in-depth (e.g. SSL pinning, RASP) for high-value targets.
  • Forensic memory dump while the app is unlocked. Decrypted values transit through React Native's JSI as standard JS strings; we do not zeroize the heap.
  • OS-level exploits / supply-chain compromise of the OEM. Hardware-backed protection is only as strong as the chain of trust ending at the secure element vendor.
  • Side-channel timing attacks against the native crypto. We rely on platform primitives (CryptoKit, AndroidX Security). These have not been audited for timing in this codebase.
  • Screenshots, accessibility services, and screen recording. Values rendered to the UI are visible to anything that can read the screen.
  • Phishing/social engineering. Biometric prompts cannot tell who is actually pressing the finger.

Fallback ladder

The native layer continuously downgrades to the strongest scheme the device supports. Always inspect StorageMetadata.securityLevel after writing to confirm what the platform applied.

secureEnclave  →  strongBox  →  biometry  →  deviceCredential  →  software
       (best)                                                       (worst)
TieriOSAndroid
secureEnclaveKeys generated/used inside the Secure Enclave
strongBoxTamper-resistant secure element (Android 9+ where present)
biometryHardware-backed Keychain + biometric ACLKeystore key with setUserAuthenticationRequired(true)
deviceCredentialHardware-backed Keychain + device passcode ACLKeystore key with passcode-only auth
softwareSoftware fallback (simulators, very old devices)EncryptedSharedPreferences fallback

If you hold compliance constraints (e.g. PCI/HIPAA), refuse to write secrets when metadata.securityLevel === 'software'. Reading the level requires no biometric prompt (includeValues: false is enough).

  1. Request accessControl: 'secureEnclaveBiometry'.
  2. Verify metadata.securityLevel ∈ {'secureEnclave', 'strongBox'} after write — refuse otherwise.
  3. Rotate keys (rotateKeys) on a calendar (e.g. quarterly) or on suspicious-activity signals.
  4. Catch KeyInvalidatedError and IntegrityViolationError separately — they imply different user-facing flows (re-onboard vs. force re-auth + telemetry).
  5. Don't call getItem from background tasks unless you also pass authenticationPrompt. iOS silently fails biometric reads outside foreground.