Full Report
The author of this post was reverse-engineering a mobile application for weird handling of deeplinks. While doing this, they found a Browsable intent-filter with a custom Schema. Additionally, the app had a WebView with no host restrictions and a NativeMessage handler that uses postMessage. Altogether, this functionality created a large attack surface to explore, so they decided to dig in. The NativeMessageHandler() JSInterface (webview to native) only had a single exported message: postMessage. It had two types of actions: Native and Standard. After registering yourself as a sender, there were actions like sharing/saving files and more. This code contained an arbitrary file write via a path traversal. Classic! The author began to ask themselves was the consequence of this was though. The application they were testing used React Over the Air updates to allow for updating JavaScript bundles without going through the app store for review. After playing around with these directories, they found the right information to write to gain RCE on the Android device after an app crash. The deeplink didn't work for ALL URLs; it had a server-side check that verifies whether an endpoint is trusted or not. One of the trusted domains was google.com and its subdomains. Google has a subdomain called sites.google.com that allows for loading arbitrary webpages through an iframe. From this iframe, it was possible to use postMessage to trigger the bug once again. This is the full exploit path: Route a browser on Android to a deeplink to the application with the special Google site iframe from above. Register the native handler. Overwrite the OTA configuration and creates a malicious React Native bundle. Restart the application. This can be done by crashing the app or waiting for the user to restart. The company runs an AI security company. They were able to replicate the finding of this vulnerability using this tool. This appeared to take some guidance to find though. A very crazy chain of issues that led to a sick RCE. Great post!
Analysis Summary
# Vulnerability: Remote Code Execution via WebView JSInterface and Path Traversal
## CVE Details
- **CVE ID:** Not explicitly assigned in the report (0-day/Bounty discovery)
- **CVSS Score:** 9.6 (Critical) - *Estimated based on remote exploit chain*
- **CWE:** CWE-22 (Path Traversal), CWE-749 (Exposed Dangerous Method or Interface), CWE-94 (Code Injection)
## Affected Systems
- **Products:** Unnamed Android application (Referred to as "Target App")
- **Versions:** All versions prior to the January 2026 disclosure.
- **Configurations:**
- Apps using **React Native** with Over-the-Air (OTA) update mechanisms.
- Exported `MainActivity` with **Browsable** intent-filters and custom schemes.
- WebViews with no host restrictions and exposed `JSInterface`.
## Vulnerability Description
The vulnerability stems from an insecurely configured `NativeMessageHandler` JavaScript Interface (JSInterface) within a WebView. The application exposed a `postMessage` method that allowed any website (regardless of domain) to register as a "Native" sender.
Once registered, an attacker could trigger a `shareContent` function that failed to sanitize the `fileName` parameter. This led to an **arbitrary file write** via path traversal. By overwriting the application's internal React Native OTA configuration files (`OTAPrefs.xml`) and the JavaScript bundle (`index.android.bundle`), an attacker could redirect the app logic to execute malicious code upon the next app launch.
## Exploitation
- **Status:** PoC available; demonstrated to vendor.
- **Complexity:** Medium (Requires chaining multiple logical flaws).
- **Attack Vector:** Network (Remote via malicious URL).
### Exploit Steps
1. **Initial Access:** Redirect the victim to a `targetapp://` deeplink.
2. **Bypass:** Use a trusted subdomain (e.g., `sites.google.com`) to host an iframe that bypasses server-side "trusted host" checks.
3. **Handshake:** The iframe communicates with `window.NativeMessageHandler` to escalate privileges to "Native" sender.
4. **Traversal:** Call `shareContent` with `../../shared_prefs/OTAPrefs.xml` to point the app to a malicious bundle.
5. **Payload:** Write the malicious Hermes JS bundle to the local filesystem.
6. **Execution:** On app restart, the malicious bundle executes, exfiltrating keychains and session cookies.
## Impact
- **Confidentiality:** High (Full access to auth tokens, session cookies, and internal files).
- **Integrity:** High (Ability to overwrite application logic and update bundles).
- **Availability:** High (Persistent control over the application; ability to crash or disable the app).
## Remediation
### Patches
- **Vendor Fix:** The vendor has reportedly patched the path traversal in the `shareContent` handler and implemented stricter host validation for the JSInterface.
- **Version:** Users should update to the latest version via the Google Play Store.
### Workarounds
- Disable the JSInterface for untrusted domains.
- Ensure the `setAllowFileAccess(false)` and `setAllowContentAccess(false)` flags are set in WebView settings.
- Implement strict allow-listing for all deeplink destinations.
## Detection
- **Indicators of Compromise:**
- Unexpected modifications to `/data/data/[pkg]/shared_prefs/OTAPrefs.xml`.
- Unusual `postMessage` calls to `NativeMessageHandler` from unauthorized domains.
- Deeplinks containing URL-encoded path traversal characters (`../`).
- **Detection methods:** Static analysis (SAST) to identify un-sanitized file writes and dynamic analysis (DAST) to monitor WebView IPC.
## References
- hxxps[://]djini[.]ai/2026/01/22/from-webview-to-remote-code-injection/
- hxxps[://]djini[.]ai/author/lyes/