Skip to content

Latest commit

 

History

History
68 lines (57 loc) · 4.21 KB

File metadata and controls

68 lines (57 loc) · 4.21 KB

Threat Model

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)
Tier iOS Android
secureEnclave Keys generated/used inside the Secure Enclave
strongBox Tamper-resistant secure element (Android 9+ where present)
biometry Hardware-backed Keychain + biometric ACL Keystore key with setUserAuthenticationRequired(true)
deviceCredential Hardware-backed Keychain + device passcode ACL Keystore key with passcode-only auth
software Software 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).

Recommended posture for high-value secrets

  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.