Field notes
3 min read

The Atomic App Scanner now reads React Native Android apps

Most of the logic in a React Native app lives in the JavaScript bundle, not in the Java code the scanner was originally built to inspect. It now reads that bundle too, whether it ships as plain JavaScript or as compiled Hermes bytecode.

mobilereact-nativescanner

Most of what a React Native app does never touches Java or Kotlin. The screens, the API calls, the auth logic, they all live in a JavaScript bundle that ships inside the APK. A scanner that only walks the DEX never sees any of it. The Atomic App Scanner was built to read Java code, so React Native apps only ever got a partial scan. As of today it reads the bundle too.

The real code lives in the JavaScript bundle

Open a React Native Android build and the Java side is mostly scaffolding: the bridge, a couple of native modules, and the glue that hands control to the JavaScript runtime. The real logic sits in assets/index.android.bundle. That is where an app pastes an API key into a const, calls an endpoint over http://, or writes a token to AsyncStorage. Scan only the DEX and you have checked the wrapper. The code that does the actual work goes unchecked.

Two kinds of bundle

Older builds ship the bundle as a single minified JavaScript file. Newer ones default to Hermes, which compiles the JavaScript ahead of time into its own bytecode, so there is no readable source left to grep. Run strings on a Hermes bundle and you mostly get noise, which is where a lot of tooling gives up. The scanner handles both: plain JavaScript and Hermes bytecode.

Nothing to configure

Upload the APK the way you always have. The scanner spots the React Native build, unpacks the bundle, and runs the JavaScript checks as part of the same scan. There is no flag to set and no source code needed, it just reads the release you actually ship.

New React Native rules

If you have a React Native app on Android, here is what the scan now picks up, grouped by what each rule touches:

  • Platform (WebView)

    • code.react_native.webview_dangerous_config: react-native-webview with sandbox-weakening props (allowUniversalAccessFromFileURLs / allowFileAccess+javaScriptEnabled)
  • Network / transport

    • code.react_native.cleartext_endpoint: an http:// URL passed to a network call in the bundle
    • code.react_native.metro_dev_url: a Metro dev-server URL shipped in a release bundle
  • Auth / crypto

    • code.react_native.client_jwt_trust: client-side JWT decoded and an authz decision made on the unverified claim
    • code.react_native.weak_crypto: AES-ECB mode in crypto-js usage
  • Storage / secrets

    • code.react_native.insecure_asyncstorage: a credential-shaped key written to (unencrypted) AsyncStorage
    • code.react_native.sourcemap_leak: a .bundle.map / .jsbundle.map shipped in the APK
  • Supply chain

    • code.react_native.vulnerable_npm_dep: bundled npm lib fingerprint (lodash) → npm OSV advisories, version-unconfirmed (new this session)
    • code.react_native.vulnerable_rn_version: recovered react-native core version → npm OSV advisories
  • Attack-surface inventory (observation)

    • code.react_native.bridge_attack_surface: native @ReactMethod/TurboModule methods exposed to JS, split app-owned vs bundled-library
  • Attacker-influenceable parameter from JS (dangerous native sink)

    • code.react_native_bridge.command_exec → Runtime.exec
    • code.react_native_bridge.sql_injection → SQLiteDatabase query
    • code.react_native_bridge.dynamic_code_load → dynamic class/dex loading
    • code.react_native_bridge.reflection → reflection
    • code.react_native_bridge.url_injection → network URL
    • code.react_native_bridge.webview_load → WebView loader
    • code.react_native_bridge.file_path → new File() / filesystem path
  • Interprocedural secret→sink taint

    • code.react_native.secret_to_cleartext → secret cleartext http fetch (cross-module)
    • code.react_native.secret_logged → secret log sink
    • code.react_native.secret_insecure_storage → secret unencrypted storage sink

Run the same 88 analyzers on your Android APK. Your first scan is free, no card.

Scan your APK free