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