
Avis public et PoC pour CVE-2026-26897 — Contournement de deep link dans EcoOnline EHS Android (com.airsweb.v10), corrigé en 0.2.500
Divulgation publique / avis pour CVE-2026-26897, un contournement de validation de deep link dans l'application Android EcoOnline EHS (com.airsweb.v10). Un deep link ehs-app:// spécialement conçu est réécrit en https:// et chargé directement dans la WebView principale de l'application sans le contrôle de liste blanche d'hôtes que l'application applique sur tous les autres chemins de navigation, permettant à un attaquant distant d'afficher du contenu arbitraire contrôlé par l'attaquant dans l'application de confiance (hameçonnage).
Divulgation responsable, reconnue par l'éditeur et corrigée dans la version 0.2.500.
com.airsweb.v10 0.2.499 (versionCode 44631)L'application de l'éditeur est propriétaire et n'est pas redistribuée dans ce dépôt. L'analyse statique ci-dessous a été effectuée sur la build identifiée ici — obtenez l'APK exact depuis une archive (par exemple l'historique des versions d'APKPure) et vérifiez son hash avant de reproduire :
| Package | com.airsweb.v10 |
| versionName / versionCode | 0.2.499 / 44631 |
EcoOnline EHS pour Android est un wrapper WebView Jetpack-Compose autour de la plateforme web EHS. Son contenu par défaut est chargé depuis :
startUrl = "https://ehsmobilelanding.ecoonline.net/"
L'application expose une seule Activity (MainActivity) qui est à la fois le lanceur et le gestionnaire du schéma d'URL personnalisé ehs-app. L'élément <data> de l'intent-filter du deep link déclare uniquement un schéma — ni hôte ni chemin — de sorte que toute URI ehs-app://… est routée vers l'application.
Pour protéger la navigation de la WebView, l'application implémente une liste blanche d'hôtes (isInternalHost) et l'applique lors de la restauration de la dernière URL visitée. Cependant, la branche de gestion des deep links n'appelle pas du tout cette liste blanche. Elle prend l'URI du deep link entrant, effectue un remplacement de chaîne naïf du schéma ehs-app: → https:, puis appelle WebView.loadUrl() sur le résultat. Un attaquant distant peut donc concevoir un deep link qui amène l'application de confiance à charger une origine https:// arbitraire.
AndroidManifest.xml (v0.2.499) — deep link exporté, schéma uniquement<activity
android:name="com.airsweb.v10.MainActivity"
android:exported="true" ... >
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="ehs-app"/> <!-- scheme only: no host, no path -->
</intent-filter>
</activity>
MainActivityKt.WebViewPage (décompilé, v0.2.499)// 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); // <-- NO isInternalHost() CHECK
}
}
La liste blanche que ce chemin n'applique pas (utilisée ailleurs dans le même fichier) :
private static final Regex internalDomains =
new Regex("^[-\\w]*\\.(airsweb)|(ecoonline)\\.net");
private static final List<String> 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);
}
Note secondaire : la regex
internalDomainsest elle-même faible (alternance cassée + correspondance de sous-chaînecontainsMatchIn), mais le problème principal est que la branche deep link n'appelle jamaisisInternalHost.
Une preuve de concept (PoC) par enregistrement d'écran a été réalisée le 2026-01-13 contre com.airsweb.v10 0.2.499.
ehs-app://attacker.example/login
MainActivity réécrit le schéma et la WebView charge :
https://attacker.example/login
Une démonstration bénigne, sans collecte d'identifiants de la redirection est incluse dans poc/redirect-proof.html (utilisation : poc/README.md). Elle prouve qu'une origine arbitraire est chargée dans l'application de confiance, sans aucune saisie, sans capture d'identifiants et sans requêtes réseau.
Dans la PoC d'origine, le chercheur a hébergé une page d'atterrissage bénigne imitant l'application uniquement pour démontrer la redirection. Cet avis documente la vulnérabilité à des fins défensives / de divulgation et ne contient intentionnellement aucune page de hameçonnage ni code de capture d'identifiants.
https:// arbitraire contrôlé par l'attaquant dans le contexte de l'application de confiance.CVSS v3.1 (estimation du chercheur — à finaliser avant publication) :
AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N → 6.3 (Moyen) (un argument de Scope:Changed peut être avancé, car le contenu non fiable s'exécute dans le contexte de l'application de confiance).
Mettez à jour vers com.airsweb.v10 0.2.500 ou une version ultérieure. Correctifs recommandés :
isInternalHost() (ou une liste blanche équivalente) aux URL des deep links avant loadUrl().intent-filter du deep link avec un android:host/android:pathPrefix explicite.internalDomains (ancrez complètement l'hôte ; évitez les correspondances de sous-chaînes).Découvert et signalé par Ahmet Mersin — GitHub @iwallplace, HackerOne iwallplace.
| SHA-256 | e9e8a38d133cb9da9901caf03c4a7a033c75ad1f32ba0539260e47d5dd5068c0 |
| Source | APKPure — « EcoOnline EHS » historique des versions |
| Champ | Valeur |
|---|
| ID CVE | CVE-2026-26897 |
| Éditeur | EcoOnline ("EcoOnline Global") — https://www.ecoonline.com/ |
| Produit | EcoOnline EHS pour Android (com.airsweb.v10) |
| Version affectée | 0.2.499 (versionCode 44631) |
| Version corrigée | 0.2.500 |
| Type de vulnérabilité | Validation incorrecte dans un gestionnaire de schéma d'URL personnalisé (contournement de deep link) → chargement WebView non validé / open redirect |
| CWE | CWE-939 (Autorisation inappropriée dans le gestionnaire de schéma d'URL personnalisé) ; CWE-749 associée |
| Composant affecté | com.airsweb.v10.MainActivity (gestionnaire de deep link exporté) et la branche deep link dans MainActivityKt.WebViewPage |
| Schéma personnalisé | ehs-app:// |
| Type d'attaque | À distance (nécessite une interaction de l'utilisateur — ouverture d'un lien spécialement conçu) |
| Impact | Hameçonnage / ingénierie sociale : contenu web arbitraire contrôlé par l'attaquant affiché dans l'application de confiance EcoOnline EHS (par ex. une fausse page de connexion), contournant la liste blanche de domaines de l'application |
| Découvreur | Ahmet Mersin |
| Date | Événement |
|---|
| 2026-01-13 | PoC enregistrée contre 0.2.499 |
| 2026-01-15 | Demande de CVE soumise à MITRE (ticket scr1979357) |
| 2026-02-27 | CVE-2026-26897 attribué par MITRE |
| avant publication | L'éditeur a reconnu la vulnérabilité ; correctif publié dans 0.2.500 |
| 2026-03-04 | Demande de publication envoyée à MITRE |
| 2026-05-06 | MITRE a demandé une URL de divulgation publique complète |
| 2026-06-03 | Avis public publié (ce dépôt) |