Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1"
android:versionName="1.0"
android:compileSdkVersion="35"
android:compileSdkVersionCodename="15"
package="org.owasp.mastestapp"
platformBuildVersionCode="35"
platformBuildVersionName="15">
<uses-sdk
android:minSdkVersion="29"
android:targetSdkVersion="35"/>
<uses-permission android:name="android.permission.INTERNET"/>
<permission
android:name="org.owasp.mastestapp.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION"
android:protectionLevel="signature"/>
<uses-permission android:name="org.owasp.mastestapp.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION"/>
<application
android:theme="@style/Theme.MASTestApp"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:debuggable="true"
android:allowBackup="true"
android:supportsRtl="true"
android:extractNativeLibs="false"
android:usesCleartextTraffic="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:appComponentFactory="androidx.core.app.CoreComponentFactory">
<activity
android:theme="@style/Theme.MASTestApp"
android:name="org.owasp.mastestapp.MainActivity"
android:exported="true">
<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="vulnerable-app"
android:host="deeplink"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name="androidx.compose.ui.tooling.PreviewActivity"
android:exported="true"/>
<activity
android:name="androidx.activity.ComponentActivity"
android:exported="true"/>
<provider
android:name="androidx.startup.InitializationProvider"
android:exported="false"
android:authorities="org.owasp.mastestapp.androidx-startup">
<meta-data
android:name="androidx.emoji2.text.EmojiCompatInitializer"
android:value="androidx.startup"/>
<meta-data
android:name="androidx.lifecycle.ProcessLifecycleInitializer"
android:value="androidx.startup"/>
<meta-data
android:name="androidx.profileinstaller.ProfileInstallerInitializer"
android:value="androidx.startup"/>
</provider>
<receiver
android:name="androidx.profileinstaller.ProfileInstallReceiver"
android:permission="android.permission.DUMP"
android:enabled="true"
android:exported="true"
android:directBootAware="false">
<intent-filter>
<action android:name="androidx.profileinstaller.action.INSTALL_PROFILE"/>
</intent-filter>
<intent-filter>
<action android:name="androidx.profileinstaller.action.SKIP_FILE"/>
</intent-filter>
<intent-filter>
<action android:name="androidx.profileinstaller.action.SAVE_PROFILE"/>
</intent-filter>
<intent-filter>
<action android:name="androidx.profileinstaller.action.BENCHMARK_OPERATION"/>
</intent-filter>
</receiver>
</application>
</manifest>
32 changes: 32 additions & 0 deletions demos/android/MASVS-PLATFORM/MASTG-DEMO-0062/MASTG-DEMO-0062.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
platform: android
title: Unvalidated URL from Deep Link Loaded in WebView with semgrep
id: MASTG-DEMO-0062
code: [kotlin]
test: MASTG-TEST-0288
status: new
---

### Sample

The following is a sample code file that contains a function to handle a deep link, which insecurely loads a URL into a WebView.

{{ MastgTest.kt # MastgTest_reversed.java }}

### Steps

Let's run @MASTG-TOOL-0110 rules against the sample code.

{{ ../../../../rules/mastg-android-unvalidated-deeplink-data.yml }}

{{ run.sh }}

### Observation

The output file shows usage of dangerous data flow from a source `getQueryParameter` to a sink `loadUrl`.

{{ output.txt }}

### Evaluation

The test fails because the app loads a user-controllable URL from a deep link directly into a WebView without validation.
32 changes: 32 additions & 0 deletions demos/android/MASVS-PLATFORM/MASTG-DEMO-0062/MastgTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.owasp.mastestapp

import android.annotation.SuppressLint
import android.content.Context
import android.net.Uri
import android.webkit.WebView
import androidx.activity.ComponentActivity

class MastgTest(private val context: Context) {

fun mastgTest(): String {
return """
This app is vulnerable to deep link attacks.

Test with:
adb shell am start -a android.intent.action.VIEW -d "vulnerable-app://deeplink?url=https://example.com"
""".trimIndent()
}

@SuppressLint("SetJavaScriptEnabled")
fun processDeepLinkAndLoad(uri: Uri?) {
if (uri == null) return

val url = uri.getQueryParameter("url")
if (url != null) {
val webView = WebView(context)
webView.settings.javaScriptEnabled = true
webView.loadUrl(url)
(context as ComponentActivity).setContentView(webView)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.owasp.mastestapp;

import android.content.Context;
import android.net.Uri;
import android.webkit.WebView;
import androidx.activity.ComponentActivity;
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;

/* compiled from: MastgTest.kt */
@Metadata(d1 = {"\u0000$\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0018\u0002\n\u0002\b\u0003\n\u0002\u0010\u000e\n\u0000\n\u0002\u0010\u0002\n\u0000\n\u0002\u0018\u0002\n\u0000\b\u0007\u0018\u00002\u00020\u0001B\u000f\u0012\u0006\u0010\u0002\u001a\u00020\u0003¢\u0006\u0004\b\u0004\u0010\u0005J\u0006\u0010\u0006\u001a\u00020\u0007J\u0012\u0010\b\u001a\u00020\t2\b\u0010\n\u001a\u0004\u0018\u00010\u000bH\u0007R\u000e\u0010\u0002\u001a\u00020\u0003X\u0082\u0004¢\u0006\u0002\n\u0000¨\u0006\f"}, d2 = {"Lorg/owasp/mastestapp/MastgTest;", "", "context", "Landroid/content/Context;", "<init>", "(Landroid/content/Context;)V", "mastgTest", "", "processDeepLinkAndLoad", "", "uri", "Landroid/net/Uri;", "app_debug"}, k = 1, mv = {2, 0, 0}, xi = 48)
/* loaded from: classes3.dex */
public final class MastgTest {
public static final int $stable = 8;
private final Context context;

public MastgTest(Context context) {
Intrinsics.checkNotNullParameter(context, "context");
this.context = context;
}

public final String mastgTest() {
return "This app is vulnerable to deep link attacks.\n\nTest with:\nadb shell am start -a android.intent.action.VIEW -d \"vulnerable-app://deeplink?url=https://example.com\"";
}

public final void processDeepLinkAndLoad(Uri uri) {
String url;
if (uri != null && (url = uri.getQueryParameter("url")) != null) {
WebView webView = new WebView(this.context);
webView.getSettings().setJavaScriptEnabled(true);
webView.loadUrl(url);
Context context = this.context;
Intrinsics.checkNotNull(context, "null cannot be cast to non-null type androidx.activity.ComponentActivity");
((ComponentActivity) context).setContentView(webView);
}
}
}
12 changes: 12 additions & 0 deletions demos/android/MASVS-PLATFORM/MASTG-DEMO-0062/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@



┌────────────────┐
│ 1 Code Finding │
└────────────────┘

MastgTest_reversed.java
❯❱ android-unvalidated-deeplink-data
[MASVS-PLATFORM] Unvalidated deep link query parameters are directly loaded into a WebView.

31┆ webView.loadUrl(url);
1 change: 1 addition & 0 deletions demos/android/MASVS-PLATFORM/MASTG-DEMO-0062/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
NO_COLOR=true semgrep -c ../../../../rules/mastg-android-unvalidated-deeplink-data.yml ./MastgTest_reversed.java > output.txt
32 changes: 32 additions & 0 deletions demos/android/MASVS-PLATFORM/MASTG-DEMO-0063/MASTG-DEMO-0063.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
platform: android
title: Deep Link Intent Filter Missing android:autoVerify with semgrep
id: MASTG-DEMO-0063
code: [kotlin]
test: MASTG-TEST-0289
status: new
---

### Sample

The following is a sample `AndroidManifest.xml` snippet that defines a deep link intent filter without the `android:autoVerify="true"` attribute.

{{ ../MASTG-DEMO-0062/AndroidManifest_reversed.xml }}

### Steps

Let's run @MASTG-TOOL-0110 rules against the sample manifest.

{{ ../../../../rules/mastg-android-autoverify-missing.yml }}

{{ run.sh }}

### Observation

The rule has identified that the deep link intent filter is missing the `android:autoVerify="true"` attribute.

{{ output.txt }}

### Evaluation

The test fails because the app does not enforce Android App Links verification. Without `android:autoVerify="true"`, malicious apps may intercept the app's deep links, leading to phishing or hijacking attacks.
19 changes: 19 additions & 0 deletions demos/android/MASVS-PLATFORM/MASTG-DEMO-0063/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@


┌────────────────┐
│ 1 Code Finding │
└────────────────┘

AndroidManifest_reversed.xml
❯❱ android-autoverify-missing
[MASVS-PLATFORM] Deep link intent filter missing android:autoVerify="true",enabling
malicious apps to hijack links.

33┆ <intent-filter>
34┆ <action android:name="android.intent.action.VIEW"/>
35┆ <category android:name="android.intent.category.DEFAULT"/>
36┆ <category android:name="android.intent.category.BROWSABLE"/>
37┆ <data
38┆ android:scheme="vulnerable-app"
39┆ android:host="deeplink"/>
40┆ </intent-filter>
1 change: 1 addition & 0 deletions demos/android/MASVS-PLATFORM/MASTG-DEMO-0063/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
NO_COLOR=true semgrep -c ../../../../rules/mastg-android-autoverify-missing.yml ../MASTG-DEMO-0062/AndroidManifest_reversed.xml --text -o output.txt
24 changes: 24 additions & 0 deletions rules/mastg-android-autoverify-missing.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
rules:
- id: android-autoverify-missing
severity: WARNING
languages:
- xml
metadata:
summary: This rule looks for insecure deep link configurations.
message: '[MASVS-PLATFORM] Deep link intent filter missing android:autoVerify="true",enabling malicious apps to hijack links.'
patterns:
- pattern-inside: |
<activity ...>
...
</activity>
- pattern: |
<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="..." />
</intent-filter>
- pattern-not: |
<intent-filter android:autoVerify="true">
...
</intent-filter>
15 changes: 15 additions & 0 deletions rules/mastg-android-unvalidated-deeplink-data.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
rules:
- id: android-unvalidated-deeplink-data
severity: WARNING
languages:
- java
metadata:
summary: This rule looks for insecure deep link configurations.
message: "[MASVS-PLATFORM] Unvalidated deep link query parameters are directly loaded into a WebView."
mode: taint
pattern-sources:
# Source: Data originating from the intent's URI parameter.
- pattern: $URI.getQueryParameter(...)
pattern-sinks:
# Sink: The unvalidated data is loaded into a WebView.
- pattern: $WEBVIEW.loadUrl(...)
24 changes: 24 additions & 0 deletions tests-beta/android/MASVS-PLATFORM/MASTG-TEST-0292.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
title: Unvalidated URL from Deep Link Loaded in WebView
platform: android
id: MASTG-TEST-0292
type: [static]
weakness: MASWE-0088
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the right MASWE should be MASWE-0071: WebViews Loading Content from Untrusted Sources

Suggested change
weakness: MASWE-0088
weakness: MASWE-0071

profiles: [L1, L2]
---

### Overview

This vulnerability arises when an app accepts a URL from an external source such as a deep link query parameter and loads it into a WebView without validation. An attacker can craft a malicious Intent containing a deep link with a harmful URL. When loaded, the WebView executes the embedded script in the app's context, resulting in a Cross-Site Scripting (XSS) vulnerability. This could allow theft of session cookies, injection of fake content, or unauthorized actions on behalf of the user.

### Steps

Run a static ancalysis tool such as @MASTG-TOOL-0110 on the codebase to detect data flows from deep link parameters (e.g., `getQueryParameter()`) to dangerous sinks (e.g., `WebView.loadUrl()`).

### Observation

The output file shows a data flow where data from an Intent is used in `WebView.loadUrl()` without prior sanitization or validation.

### Evaluation

The test fails due to the application loading an unvalidated URL from an untrusted Intent extra into a WebView. A malicious application can create an Intent with a deep link containing a URL pointing to a malicious website. When this URL is loaded by the vulnerable WebView, the user is redirected to the attacker's site.
24 changes: 24 additions & 0 deletions tests-beta/android/MASVS-PLATFORM/MASTG-TEST-0293.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
title: Deep Link Intent Filter Missing android:autoVerify
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be "Use of Unverified App Links" plus an additional "Use of Unverified Custom URL Schemes" which is now missing.

platform: android
id: MASTG-TEST-0293
type: [static]
weakness: MASWE-0058
profiles: [L1, L2]
---

### Overview

This vulnerability occurs when a deep link intent filter in `AndroidManifest.xml` lacks the `android:autoVerify="true"` attribute. Without verification, Android cannot confirm the app's ownership of the declared domain. A malicious app could register the same intent filter and intercept deep links, enabling phishing, credential theft, or hijacking of user actions.

### Steps

Run a static analysis tool such as @MASTG-TOOL-0110 on the `AndroidManifest.xml` to detect deep link intent filters that are missing the `android:autoVerify="true"` attribute.

### Observation

The output shows a `<intent-filter>` that define deep links but do not include the `android:autoVerify="true"` attribute.

### Evaluation

The test fails as App Links verification is not enforced. Without `android:autoVerify="true"`, malicious apps can hijack deep links and redirect users to attacker-controlled content.
3 changes: 3 additions & 0 deletions tests/android/MASVS-PLATFORM/MASTG-TEST-0028.md
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ScreaMy7 ⚠️ PLEASE BE CAREFUL:

I see that a lot of the information contained in this test is being lost right now. Please consider porting it all:

  • What information is knowledge and belongs in https://mas.owasp.org/MASTG/knowledge/android/MASVS-PLATFORM/MASTG-KNOW-0019/
  • What information describes best practices and should be added to a new MASTG-BEST-XXXX? (each test should have at least one best practice linked)
  • What techniques are here that don't have a MASTG-TECH-XXXX entry? e.g.
    • "Check for Deep Link Usage"
    • "Check for Correct Website Association"
    • "Monitoring Deep Links"
    • "Invoking Deep Links"
    • etc
  • What tools are used and don't have a MASTG-TOOL-XXXX entry? e.g. "Android App Link Verification Tester"
  • What tests are missing?
    • "Use of Unverified App Links"
    • "Use of Unverified Custom URL Schemes"
    • "Use of Verified App Links with Incorrect Website Association"

Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ masvs_v1_levels:
- L1
- L2
profiles: [L1, L2]
status: deprecated
covered_by: [MASTG-TEST-0292],[MASTG-TEST-0293]
deprecation_note: New version available in MASTG V2
---

## Overview
Expand Down
Loading