Skip to content

MASTG-DEMO-0156: SafeBrowsing Disabled Detection with semgrep

Download MASTG-DEMO-0156 APK Open MASTG-DEMO-0156 Folder Build MASTG-DEMO-0156 APK

Sample

The following sample explicitly enables SafeBrowsing for WebViews in the AndroidManifest.xml by setting the android.webkit.WebView.EnableSafeBrowsing meta-data to true. However, in the WebView code, SafeBrowsing is disabled via WebSettings.setSafeBrowsingEnabled(false), which takes precedence over the manifest setting. This demonstrates that the manifest setting alone is not sufficient to determine whether SafeBrowsing is enabled.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?xml version="1.0" encoding="utf-8"?>
<!-- SUMMARY: This AndroidManifest.xml sample enables SafeBrowsing for WebViews, but the setting is overridden and disabled in the Kotlin code. -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.MASTestApp"
        tools:targetApi="31">

        <!-- PASS: [MASTG-TEST-0399] SafeBrowsing is enabled, providing protection against known malicious URLs -->
        <!-- But you should still check the Kotlin code since it takes precedence. -->

        <meta-data
            android:name="android.webkit.WebView.EnableSafeBrowsing"
            android:value="true" />

        <activity
            android:name=".MainActivityWebView"
            android:exported="true"
            android:windowSoftInputMode="adjustResize"
            android:theme="@style/Theme.MASTestApp">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
<?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:testOnly="true"
        android:allowBackup="true"
        android:supportsRtl="true"
        android:extractNativeLibs="false"
        android:fullBackupContent="@xml/backup_rules"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:appComponentFactory="androidx.core.app.CoreComponentFactory"
        android:dataExtractionRules="@xml/data_extraction_rules">
        <meta-data
            android:name="android.webkit.WebView.EnableSafeBrowsing"
            android:value="true"/>
        <activity
            android:theme="@style/Theme.MASTestApp"
            android:name="org.owasp.mastestapp.MainActivityWebView"
            android:exported="true"
            android:windowSoftInputMode="adjustResize">
            <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:theme="@android:style/Theme.Material.Light.NoActionBar"
            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>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package org.owasp.mastestapp

import android.content.Context
import android.os.Build
import android.util.Log
import android.webkit.SafeBrowsingResponse
import android.webkit.WebResourceRequest
import android.webkit.WebView
import android.webkit.WebViewClient

// SUMMARY: This sample demonstrates an app that disables WebView SafeBrowsing at runtime, which takes precedence over the AndroidManifest setting.

class MastgTestWebView(private val context: Context) {

    fun mastgTest(webView: WebView) {
        webView.apply {

            // FAIL: [MASTG-TEST-0399] SafeBrowsing is disabled in code, overriding the manifest and removing protection against known malicious URLs.
            settings.safeBrowsingEnabled = false

            webViewClient = object : WebViewClient() {
                override fun onSafeBrowsingHit(
                    view: WebView,
                    request: WebResourceRequest,
                    threatType: Int,
                    callback: SafeBrowsingResponse
                ) {
                    Log.d("SafeBrowsing", "Blocked URL, ${request.url}, threatType, $threatType")

                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
                        callback.backToSafety(true)
                    } else {
                        super.onSafeBrowsingHit(view, request, threatType, callback)
                    }
                }
            }

            loadUrl("chrome://safe-browsing/match?type=phishing")
        }
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package org.owasp.mastestapp;

import android.content.Context;
import android.util.Log;
import android.webkit.SafeBrowsingResponse;
import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;

/* JADX INFO: compiled from: MastgTestWebView.kt */
/* JADX INFO: loaded from: classes3.dex */
@Metadata(d1 = {"\u0000\u001e\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0018\u0002\n\u0002\b\u0003\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\u000e\u0010\u0006\u001a\u00020\u00072\u0006\u0010\b\u001a\u00020\tR\u000e\u0010\u0002\u001a\u00020\u0003X\u0082\u0004¢\u0006\u0002\n\u0000¨\u0006\n"}, d2 = {"Lorg/owasp/mastestapp/MastgTestWebView;", "", "context", "Landroid/content/Context;", "<init>", "(Landroid/content/Context;)V", "mastgTest", "", "webView", "Landroid/webkit/WebView;", "app_debug"}, k = 1, mv = {2, 0, 0}, xi = 48)
public final class MastgTestWebView {
    public static final int $stable = 8;
    private final Context context;

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

    public final void mastgTest(WebView webView) {
        Intrinsics.checkNotNullParameter(webView, "webView");
        webView.getSettings().setSafeBrowsingEnabled(false);
        webView.setWebViewClient(new WebViewClient() { // from class: org.owasp.mastestapp.MastgTestWebView$mastgTest$1$1
            @Override // android.webkit.WebViewClient
            public void onSafeBrowsingHit(WebView view, WebResourceRequest request, int threatType, SafeBrowsingResponse callback) {
                Intrinsics.checkNotNullParameter(view, "view");
                Intrinsics.checkNotNullParameter(request, "request");
                Intrinsics.checkNotNullParameter(callback, "callback");
                Log.d("SafeBrowsing", "Blocked URL, " + request.getUrl() + ", threatType, " + threatType);
                callback.backToSafety(true);
            }
        });
        webView.loadUrl("chrome://safe-browsing/match?type=phishing");
    }
}

Steps

Let's run our semgrep rule against the reverse-engineered manifest and code. The rule flags SafeBrowsing being disabled, either via the EnableSafeBrowsing meta-data set to false in the AndroidManifest.xml or via a WebSettings.setSafeBrowsingEnabled(false) call in the WebView code.

../../../../rules/mastg-android-webview-safebrowsing.yml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
rules:
  - id: mastg-android-webview-safebrowsing-disabled-manifest
    severity: WARNING
    languages:
      - xml
    metadata:
      summary: This rule detects when SafeBrowsing is explicitly disabled for WebViews in the AndroidManifest.xml.
    message: "[MASVS-CODE-4] SafeBrowsing is disabled for WebViews in the AndroidManifest (EnableSafeBrowsing set to false). This removes an important security protection against known malicious URLs."
    patterns:
      - pattern: |
          <meta-data android:name="android.webkit.WebView.EnableSafeBrowsing" android:value="false" ... />

  - id: mastg-android-webview-safebrowsing-disabled-code
    severity: WARNING
    languages:
      - java
    metadata:
      summary: This rule detects when SafeBrowsing is explicitly disabled for WebViews at runtime via WebSettings.setSafeBrowsingEnabled(false).
    message: "[MASVS-CODE-4] SafeBrowsing is disabled for WebViews in code via setSafeBrowsingEnabled(false). This takes precedence over the AndroidManifest and removes an important security protection against known malicious URLs."
    pattern: $WEBSETTINGS.setSafeBrowsingEnabled(false)
run.sh
1
2
#!/bin/bash
NO_COLOR=true semgrep -c ../../../../rules/mastg-android-webview-safebrowsing.yml ./AndroidManifest_reversed.xml ./MastgTestWebView_reversed.java --text -o output.txt

Observation

The output shows that SafeBrowsing is disabled in the WebView code via setSafeBrowsingEnabled(false).

output.txt
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
┌────────────────┐
 1 Code Finding 
└────────────────┘

    MastgTestWebView_reversed.java
    ❯❱ rules.mastg-android-webview-safebrowsing-disabled-code
          [MASVS-CODE-4] SafeBrowsing is disabled for WebViews in code via setSafeBrowsingEnabled(false). This
          takes precedence over the AndroidManifest and removes an important security protection against known
          malicious URLs.                                                                                     

           26 webView.getSettings().setSafeBrowsingEnabled(false);

Evaluation

The test case fails because the WebView code disables SafeBrowsing via WebSettings.setSafeBrowsingEnabled(false) (reported on line 26 of the reverse-engineered code). Even though the android.webkit.WebView.EnableSafeBrowsing meta-data is set to android:value="true" in the manifest, the code setting takes precedence, so SafeBrowsing is disabled for all WebViews in the app, removing an important security layer that protects users from known malicious URLs. This is why the WebView code must be checked in addition to the manifest.

If you remove the call to WebSettings.setSafeBrowsingEnabled(false), SafeBrowsing is enabled by default and the runtime logcat shows it blocking known malicious URLs, as shown below:

2026-06-28 10:53:56.746 10662-10662 SafeBrowsing            org.owasp.mastestapp                 D  Blocked URL, chrome://safe-browsing/match?type=phishing, threatType, 2
2026-06-28 10:53:56.748 10662-10662 SafeBrowsing            org.owasp.mastestapp                 D  Blocked URL, chrome://safe-browsing/match?type=phishing, threatType, 2