Skip to content

MASTG-DEMO-0157: Uses of WebViewClient URL Loading Handlers with semgrep

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

Sample

The following sample demonstrates how a WebViewClient is configured to intercept URL loading in a WebView. The shouldOverrideUrlLoading method is implemented to handle navigation requests, which overrides the default behavior of opening links in the default browser.

 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.util.Log
import android.webkit.WebResourceRequest
import android.webkit.WebView
import android.webkit.WebViewClient

// SUMMARY: This sample demonstrates a WebView with a custom WebViewClient that intercepts URL loading without proper validation.

class MastgTestWebView(private val context: Context) {

    fun mastgTest(webView: WebView): String {
        // Configure WebView settings
        webView.settings.apply {
            javaScriptEnabled = true
        }

        // FAIL: [MASTG-TEST-0398] Custom WebViewClient intercepts URL loading without proper validation
        webView.webViewClient = object : WebViewClient() {
            override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
                val url = request?.url?.toString()
                // No URL validation is performed - any URL will be loaded
                Log.d("MastgTest", "Loading URL: $url")
                return false // Allow the WebView to load the URL
            }

            override fun shouldInterceptRequest(view: WebView?, request: WebResourceRequest?): android.webkit.WebResourceResponse? {
                val url = request?.url?.toString()
                Log.d("MastgTest", "Intercepting request: $url")
                // No validation - allow all requests
                return super.shouldInterceptRequest(view, request)
            }
        }

        // Load a trusted page initially
        webView.loadUrl("https://mas.owasp.org/")

        return "WebView configured with custom URL handling"
    }
}
 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
package org.owasp.mastestapp;

import android.content.Context;
import android.net.Uri;
import android.util.Log;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebSettings;
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\u000e\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 String mastgTest(WebView webView) {
        Intrinsics.checkNotNullParameter(webView, "webView");
        WebSettings $this$mastgTest_u24lambda_u240 = webView.getSettings();
        $this$mastgTest_u24lambda_u240.setJavaScriptEnabled(true);
        webView.setWebViewClient(new WebViewClient() { // from class: org.owasp.mastestapp.MastgTestWebView.mastgTest.2
            @Override // android.webkit.WebViewClient
            public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
                Uri url;
                String url2 = (request == null || (url = request.getUrl()) == null) ? null : url.toString();
                Log.d("MastgTest", "Loading URL: " + url2);
                return false;
            }

            @Override // android.webkit.WebViewClient
            public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
                Uri url;
                String url2 = (request == null || (url = request.getUrl()) == null) ? null : url.toString();
                Log.d("MastgTest", "Intercepting request: " + url2);
                return super.shouldInterceptRequest(view, request);
            }
        });
        webView.loadUrl("https://mas.owasp.org/");
        return "WebView configured with custom URL handling";
    }
}

Steps

Let's run our semgrep rules against the sample code.

../../../../rules/mastg-android-webview-url-handlers.yml
 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
rules:
  - id: mastg-android-webviewclient-url-handlers
    severity: INFO
    languages:
      - java
    metadata:
      summary: This rule detects WebViewClient methods that intercept URL loading, including shouldOverrideUrlLoading and shouldInterceptRequest.
    message: "[MASVS-CODE-4] Detected WebViewClient URL interception method."
    pattern-either:
      - pattern: |
          class $CLASS extends WebViewClient {
            ...
            $RET shouldOverrideUrlLoading(...) { ... }
            ...
          }
      - pattern: |
          class $CLASS extends WebViewClient {
            ...
            $RET shouldInterceptRequest(...) { ... }
            ...
          }
      - pattern: (WebViewClient $WVC).shouldOverrideUrlLoading(...)
      - pattern: (WebViewClient $WVC).shouldInterceptRequest(...)
      - pattern: $WEBVIEW.setWebViewClient(...)

  - id: mastg-android-webviewclient-safebrowsing-whitelist
    severity: WARNING
    languages:
      - java
    metadata:
      summary: This rule detects usage of SafeBrowsing whitelist or onSafeBrowsingHit callback which may weaken security.
    message: "[MASVS-CODE-4] Detected SafeBrowsing customization that may weaken security."
    pattern-either:
      - pattern: WebView.setSafeBrowsingWhitelist(...)
      - pattern: $WEBVIEW.setSafeBrowsingWhitelist(...)
      - pattern: |
          class $CLASS extends WebViewClient {
            ...
            void onSafeBrowsingHit(...) { ... }
            ...
          }
run.sh
1
2
#!/bin/bash
NO_COLOR=true semgrep -c ../../../../rules/mastg-android-webview-url-handlers.yml ./MastgTestWebView_reversed.java --text > output.txt

Observation

The output shows references to WebViewClient URL loading handlers.

output.txt
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
┌────────────────┐
 1 Code Finding 
└────────────────┘

    MastgTestWebView_reversed.java
      rules.mastg-android-webviewclient-url-handlers
          [MASVS-CODE-4] Detected WebViewClient URL interception method.

           30 webView.setWebViewClient(new WebViewClient() { // from class:
               org.owasp.mastestapp.MastgTestWebView.mastgTest.2            
           31     @Override // android.webkit.WebViewClient
           32     public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
           33         Uri url;
           34         String url2 = (request == null || (url = request.getUrl()) == null) ? null :
               url.toString();                                                                     
           35         Log.d("MastgTest", "Loading URL: " + url2);
           36         return false;
           37     }
           38
           39     @Override // android.webkit.WebViewClient
             [hid 7 additional lines, adjust with --max-lines-per-finding] 

Evaluation

The test fails because the WebView can load content from any host the user is directed to. The static rule flags the attack surface: the reported finding points to the setWebViewClient call and the custom WebViewClient it registers, which spans both overridden handlers. Using a WebViewClient is not insecure on its own, so as required by References to WebViewClient URL Loading Handlers we inspect each reported handler to confirm whether it restricts navigation to trusted content.

Reviewing the reported code shows that neither handler performs any validation:

  1. setWebViewClient: The WebView is configured with the custom WebViewClient.
  2. shouldOverrideUrlLoading: The implementation reads only request.getUrl().toString() to log the URL and always returns false. It never calls getHost, getScheme, or getPath, nor compares the URL against any allowlist or denylist, so every URL is allowed to load regardless of its host.
  3. shouldInterceptRequest: The implementation likewise only logs request.getUrl().toString() and falls back to super.shouldInterceptRequest, with no host, scheme, or path inspection.

Because the handlers inspect only the full URL string for logging and make no host-, scheme-, or path-based decision, they impose no restriction on navigation, and the WebView can load content from any host the user is directed to. The runtime counterpart of this conclusion is demonstrated in Runtime Use of WebViewClient URL Loading Handlers with Frida.