## https://sploitus.com/exploit?id=420BEB65-BD63-521E-90B1-5065E05B96C0
# EcoOnline EHS (Android) β Deep Link Validation Bypass β WebView Open Redirect (CVE-2026-26897)
Public disclosure / advisory for **CVE-2026-26897**, a deep link validation bypass in the
**EcoOnline EHS** Android application (`com.airsweb.v10`). A crafted `ehs-app://` deep link is
rewritten to `https://` and loaded directly into the app's main WebView **without the host
allow-list check** that the app applies on every other navigation path, letting a remote attacker
render arbitrary attacker-controlled content inside the trusted application (phishing).
Responsibly disclosed, acknowledged by the vendor, and **fixed in version 0.2.500**.
## β Status: FIXED
- **Vulnerable version analysed:** `com.airsweb.v10` **0.2.499** (versionCode `44631`)
- **Fixed version:** **0.2.500** (live on Google Play)
- **Action for users:** update the EcoOnline EHS app to the latest version.
## Affected binary (for verification)
The vendor's application is proprietary and is **not redistributed in this repository**. The static
analysis below was performed on the build identified here β obtain the exact APK from an archive
(e.g. APKPure version history) and verify its hash before reproducing:
| | |
|---|---|
| Package | `com.airsweb.v10` |
| versionName / versionCode | `0.2.499` / `44631` |
| SHA-256 | `e9e8a38d133cb9da9901caf03c4a7a033c75ad1f32ba0539260e47d5dd5068c0` |
| Source | APKPure β "EcoOnline EHS" version history |
## Summary
| Field | Value |
|---|---|
| **CVE ID** | CVE-2026-26897 |
| **Vendor** | EcoOnline ("EcoOnline Global") β https://www.ecoonline.com/ |
| **Product** | EcoOnline EHS for Android (`com.airsweb.v10`) |
| **Affected version** | 0.2.499 (versionCode 44631) |
| **Fixed version** | 0.2.500 |
| **Vulnerability type** | Improper validation in a custom URL scheme handler (deep link bypass) β unvalidated WebView load / open redirect |
| **CWE** | CWE-939 (Improper Authorization in Handler for Custom URL Scheme); related CWE-749 |
| **Affected component** | `com.airsweb.v10.MainActivity` (exported deep-link handler) and the deep-link branch in `MainActivityKt.WebViewPage` |
| **Custom scheme** | `ehs-app://` |
| **Attack type** | Remote (requires user interaction β opening a crafted link) |
| **Impact** | Phishing / social engineering: arbitrary attacker-controlled web content rendered inside the trusted EcoOnline EHS app (e.g. a fake login), bypassing the app's domain allow-list |
| **Discoverer** | Ahmet Mersin |
## Description
EcoOnline EHS for Android is a Jetpack-Compose **WebView wrapper** around the EHS web platform. Its
default content is loaded from:
```
startUrl = "https://ehsmobilelanding.ecoonline.net/"
```
The app exports a single Activity (`MainActivity`) that is both the launcher and the handler for the
custom URL scheme **`ehs-app`**. The `` element of the deep-link `intent-filter` declares
**only a scheme β no host and no path** β so *any* `ehs-app://β¦` URI is routed to the app.
To protect WebView navigation, the app implements a host allow-list (`isInternalHost`) and applies it
when restoring the last-visited URL. **However, the deep-link handling branch does not call that
allow-list at all.** It takes the incoming deep-link URI, performs a naΓ―ve string replacement of the
scheme `ehs-app:` β `https:`, and calls `WebView.loadUrl()` on the result. A remote attacker can
therefore craft a deep link that causes the trusted app to load an arbitrary `https://` origin.
## Affected component
### `AndroidManifest.xml` (v0.2.499) β exported, scheme-only deep link
```xml
```
### Root cause β deep-link branch in `MainActivityKt.WebViewPage` (decompiled, v0.2.499)
```java
// intent delivered to the exported MainActivity
if (intent.getScheme().equals("ehs-app")) {
WebView webView = ...;
if (webView != null) {
Uri data = intent.getData(); // full ehs-app://β¦ URI
String s = String.valueOf(data);
// naΓ―ve scheme rewrite: "ehs-app:" -> "https:"
String url = StringsKt.replaceFirst(s, "ehs-app:", "https:", false, 4, null);
webView.loadUrl(url); // excludeDomainsStartingWith =
listOf("passport", "login", "auth");
public static boolean isInternalHost(String host) {
for (String p : excludeDomainsStartingWith)
if (host.startsWith(p)) return false;
return internalDomains.containsMatchIn(host);
}
```
> Secondary note: the `internalDomains` regex is itself weak (broken alternation + `containsMatchIn`
> substring matching), but the primary issue is that **the deep-link branch never invokes
> `isInternalHost` at all.**
## Proof of Concept
A screen-recording PoC was produced on **2026-01-13** against `com.airsweb.v10` 0.2.499.
1. Install the affected version (**0.2.499**) on an Android device.
2. Deliver a crafted deep link to the victim (e.g. via email, SMS, chat, QR, or a web page):
```
ehs-app://attacker.example/login
```
3. When the victim opens it, `MainActivity` rewrites the scheme and the WebView loads:
```
https://attacker.example/login
```
inside the trusted EcoOnline EHS app β no allow-list check is performed.
4. The attacker page is rendered with the look and chrome of the legitimate app and can, for example,
present a fake EHS login to harvest credentials.
> In the original PoC the researcher hosted a **benign look-alike landing page** purely to
> demonstrate the redirect. This advisory documents the vulnerability for **defensive / disclosure
> purposes** and intentionally contains **no phishing page or credential-capture code**.
## Impact
- Loads arbitrary attacker-controlled `https://` content inside the trusted application context.
- Phishing / credential theft via a login prompt that appears to originate from the real app.
- UI spoofing and general social-engineering uplift (the malicious page inherits the app's trust).
**CVSS v3.1 (researcher estimate β finalise before publication):**
`AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N` β **6.3 (Medium)** (a Scope:Changed argument can be made, as
untrusted content executes in the trusted app context).
## Remediation
Update to **`com.airsweb.v10` 0.2.500** or later. Recommended fixes:
- Apply `isInternalHost()` (or an equivalent allow-list) to deep-link URLs **before** `loadUrl()`.
- Do not derive the loaded URL by blindly rewriting the scheme; validate scheme **and** host.
- Constrain the deep-link `intent-filter` with an explicit `android:host`/`android:pathPrefix`.
- Strengthen the `internalDomains` regex (anchor host fully; avoid substring matches).
## Disclosure timeline
| Date | Event |
|---|---|
| 2026-01-13 | PoC recorded against 0.2.499 |
| 2026-01-15 | CVE request submitted to MITRE (ticket scr1979357) |
| 2026-02-27 | **CVE-2026-26897** assigned by MITRE |
| prior to publication | Vendor acknowledged; fix released in 0.2.500 |
| 2026-03-04 | Publication request sent to MITRE |
| 2026-05-06 | MITRE requested a complete public disclosure URL |
| 2026-06-03 | Public advisory published (this repository) |
## References
- CVE-2026-26897 (MITRE CVE record)
- EcoOnline EHS on Google Play β https://play.google.com/store/apps/details?id=com.airsweb.v10
- Vendor β https://www.ecoonline.com/
## Credit
Discovered and reported by **Ahmet Mersin** β GitHub [@iwallplace](https://github.com/iwallplace),
HackerOne `iwallplace`.