Use this React Native mobile app security checklist to review secrets, token storage, authentication, deep links, WebViews, native permissions, dependencies, logging, and release configuration before shipping and throughout maintenance.
Overview
React Native app security is a shared responsibility between JavaScript code, native modules, backend services, build pipelines, and the operating systems that run the app. A secure release is not created by adding one library or enabling one setting. It comes from reducing exposure at each boundary and checking that security assumptions still hold after dependencies, authentication flows, and mobile platforms change.
This checklist is designed as a recurring review rather than a one-time launch task. Use it before a major release, after adding a third-party SDK, when changing sign-in or deep-link behavior, and during a monthly or quarterly engineering review. Keep evidence for each check: the commit reviewed, the build tested, the dependency report, the owner, and any accepted risk.
Start with a simple threat model. List the data the app handles, where that data moves, which components can access it, and what an attacker would gain from abuse. A commerce app, for example, may need to protect session tokens, order information, payment-provider callbacks, account recovery links, and administrative features. Its priorities will differ from those of an offline utility that stores no account data.
What to track
Secrets, tokens, and local storage
- Keep API keys, signing credentials, private certificates, and backend secrets out of the JavaScript bundle, source repository, screenshots, logs, and mobile configuration files that are distributed to users. Values shipped in an app should be treated as discoverable.
- Store refresh tokens and other high-value credentials in platform-backed secure storage, such as iOS Keychain or Android Keystore through a maintained React Native or Expo-compatible integration. Do not treat ordinary local storage, an unencrypted database, or a bundled JSON file as a secret vault.
- Define token expiry, rotation, revocation, and logout behavior. Confirm that logout removes locally held credentials and that a rejected refresh token cannot create an infinite retry loop.
- Use the minimum scope and lifetime needed for access tokens. Keep long-lived credentials away from screens, analytics events, error reports, and navigation parameters.
Authentication and authorization
Review the complete flow, not only the sign-in screen. Test account creation, password reset, multi-factor authentication, session restoration, logout, account deletion, and handling for expired or revoked sessions. The backend must enforce authorization; hiding a button or route in React Native is only a user-interface measure.
For browser-based authentication, validate the redirect flow and state protection used by the selected identity provider. Make sure an authentication response cannot be attached to the wrong session or accepted by an untrusted callback. Document which native modules, browser sessions, and backend endpoints participate so a future dependency replacement does not silently weaken the flow.
Deep links and universal links
Deep links are input, not trusted instructions. Parse links defensively, allowlist accepted schemes and hosts, and validate path, query, state, and authorization context before taking an action. A link that opens an order, resets a password, confirms an email address, or selects an account deserves more scrutiny than a link that merely opens a public screen.
- Prefer verified platform mechanisms for HTTPS links where appropriate, and register only the routes the app needs.
- Do not place access tokens or sensitive personal data in URLs. Assume links may appear in browser history, screenshots, logs, and referral systems.
- Test malformed links, unexpected hosts, duplicate parameters, expired links, logged-out users, and links received while another account is active.
- Ensure navigation guards run before data fetching or state changes, rather than after a sensitive screen has already loaded.
Teams reviewing navigation choices can also compare their route and linking model with the guidance in React Native Navigation Libraries Compared.
WebViews, network traffic, and certificate decisions
Keep WebViews narrowly scoped. Disable unnecessary capabilities, avoid injecting secrets into page content, restrict navigation targets, and establish how JavaScript-to-native messages are authenticated and validated. Treat content loaded from a remote address as untrusted unless the application has a clear reason and control for loading it.
Use HTTPS for application traffic and verify that production builds do not permit accidental insecure transport. Certificate pinning can reduce some interception risks, but it adds operational work around certificate rotation, recovery, and emergency access. Consider it only after documenting the threat model and a safe rotation plan; it should not replace server-side authentication, correct TLS configuration, or secure token handling.
Dependencies, permissions, logging, and release configuration
- Track direct and transitive dependencies, native modules, lockfile changes, and abandoned or unmaintained packages. Review permissions added by libraries rather than accepting every requested capability.
- Use automated dependency vulnerability scanning in pull requests and scheduled jobs. Pair automated findings with manual review because a reported issue may depend on an unused code path, while an unreported design flaw may still be serious.
- Redact tokens, passwords, authorization headers, personal data, and full deep-link URLs from logs and crash reports. Check both JavaScript logging and native logging.
- Separate development, staging, and production configuration. Confirm that debug menus, verbose logging, test accounts, development endpoints, source maps, and permissive network settings are not unintentionally enabled in release builds.
- Request only the native permissions needed for the feature, explain their use clearly, and test denial, revocation, and restricted states.
For broader pipeline controls, connect this review to your React Native CI/CD and deployment workflow. Security checks are more reliable when they run before an artifact reaches a store submission or internal distribution channel.
A compact threat-model worksheet
| Question | Example evidence | Owner |
|---|---|---|
| What data needs protection? | Data inventory and retention notes | Product and engineering |
| Where does it enter and leave the app? | API map, deep-link list, WebView list | Mobile team |
| What happens if a token or device is compromised? | Expiry, revocation, logout, and recovery tests | Backend and mobile |
| Which components are trusted? | Dependency, permission, and native-module review | Platform owner |
| How will an incident be detected? | Redacted logs, crash alerts, and escalation path | Operations |
Tool categories to compare
| Tool category | What to verify | Where it fits |
|---|---|---|
| Secure storage integration | Platform-backed storage, availability, backup behavior, and compatibility with the current React Native or Expo setup | Token and credential handling |
| Dependency scanner | Lockfile coverage, transitive dependencies, update workflow, and remediation visibility | Pull requests and scheduled audits |
| Static analysis and linting | Rules for unsafe patterns, secrets, imports, and native configuration | Development and CI |
| Crash and monitoring service | Redaction controls, access permissions, retention, and release mapping | Production detection |
| Dynamic and device testing | Deep-link, authentication, permission, WebView, and release-build coverage | Pre-release verification |
Tool selection should follow the risk and workflow, not the number of integrations. The testing and debugging practices in React Native Testing and Debugging Tools can help place security cases alongside functional and performance checks.
Cadence and checkpoints
Every pull request: inspect new dependencies, native permissions, URL handlers, logging changes, authentication code, and configuration files. Run secret scanning and the available dependency checks. Require a reviewer who understands the affected flow.
Before every release: test production-like builds on supported devices. Verify secure storage, logout, token expiry, deep links, permission denial, WebView navigation, certificate behavior if used, and the absence of debug configuration. Record the build identifier and test result.
Monthly or quarterly: review dependency maintenance, vulnerability findings, access to monitoring data, unused permissions, incident tickets, and the inventory of third-party SDKs. Recheck the security assumptions of backend integrations such as Firebase, Supabase, or Appwrite rather than assuming the client library makes the entire integration secure. A backend comparison can help document the boundaries in that stack: Firebase vs. Supabase vs. Appwrite for Mobile Apps.
After a major change: repeat the relevant threat-model section when changing authentication, account recovery, deep-link routes, payment flows, WebViews, secure-storage libraries, native permissions, React Native or Expo versions, or supported operating systems.
How to interpret changes
Not every scanner finding has the same urgency, and a clean scan does not prove that the app is secure. Prioritize findings by exploitability, exposed data, affected app versions, reachability in the shipped build, and whether a backend control limits the impact.
Separate three kinds of change in your review log:
- Exposure change: a new permission, deep-link route, WebView, SDK, endpoint, or stored data type increases the attack surface.
- Control change: token lifetime, certificate configuration, authorization logic, logging redaction, or release settings changes.
- Evidence change: a scanner, crash report, audit, or test reveals a new weakness or shows that an old assumption is no longer supported.
A dependency update should therefore trigger more than a version check. Confirm native build behavior, permissions, release configuration, and the security-sensitive user flows that use the package. If a finding cannot be fixed immediately, document the affected versions, mitigation, owner, deadline, and conditions that would raise its priority.
When to revisit
Make the checklist part of the release calendar, not a document opened only after an incident. Schedule a lightweight review monthly or quarterly, with a deeper review before significant releases. Revisit it immediately after a vulnerability notice, suspicious crash or log event, authentication change, new third-party integration, deep-link redesign, storage-library replacement, native permission change, or major React Native, Expo, iOS, or Android update.
When a security incident or credible finding occurs, preserve relevant logs without collecting unnecessary personal data, identify affected app and backend versions, revoke or rotate exposed credentials, and confirm whether server-side controls can limit further access. Then reproduce the path in a controlled environment, patch the root cause, add a regression test, and record what monitoring should have detected it sooner. Review distribution and release procedures so the corrected build reaches the appropriate users safely.
For the next audit, create one actionable ticket for each unchecked item, assign an owner, and attach evidence rather than a general “security reviewed” label. That habit turns a React Native app security checklist into a maintainable control for storage, deep links, dependencies, and every future release.