Low chrome Logic Error 🔧 Commit mapped

Overview

Low
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInformation leak in Sharing
DescriptionInformation leak in Sharing
ComponentSharing
Bug ClassLogic Error
Tracker497232609
Fix commit6146f6b618ea (chromium/src) +80/-8
CISA KEVNot listed
CreditedGoogle
Disclosed2026-08-25

Changed Functions

FunctionChangeNotes
if
chrome/android/java/src/org/chromium/chrome/browser/share/ShareDelegateImpl.java
modified

Files Changed

  • chrome/android/java/src/org/chromium/chrome/browser/share/ShareDelegateImpl.java
  • chrome/android/javatests/src/org/chromium/chrome/browser/share/ShareDelegateImplTest.java
  • chrome/android/junit/src/org/chromium/chrome/browser/share/ShareDelegateImplUnitTest.java
From 6146f6b618ea43cec28efe58c40b456391b8944b Mon Sep 17 00:00:00 2001
From: Shu Yang <shuyng@google.com>
Date: Mon, 06 Jul 2026 16:01:21 -0700
Subject: [PATCH] Restrict shared PDF content URIs to safe paths

An external app could trigger navigation to a nested content URI
pointing to Chrome's private file provider. If the user subsequently
shared this page, Chrome would include the private URI in the share
intent with read permission, allowing potential exfiltration of
sensitive files (e.g. passwords, netlogs) if the user selected the
malicious app in the share sheet.

This CL mitigates this by validating the PDF document URI before
sharing it. We use PdfUtils.isUriSafeForSharing to allow only
safe content URI paths (like downloaded PDFs) and block access to
Chrome's private directories. Unsafe URIs will fallback to a plain
URL share without granting read permissions.

Bug: 497232609
Change-Id: I1b63a2d0a7254571f80e788a26e7fff3871bd07d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8040877
Reviewed-by: Sirisha Kavuluru <skavuluru@google.com>
Commit-Queue: Shu Yang <shuyng@google.com>
Cr-Commit-Position: refs/heads/main@{#1657542}
---

diff --git a/chrome/android/java/src/org/chromium/chrome/browser/share/ShareDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/share/ShareDelegateImpl.java
index a66190f..e6f25a2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/share/ShareDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/share/ShareDelegateImpl.java
@@ -259,13 +259,17 @@
             @ShareOrigin final int shareOrigin,
             final boolean shareDirectly) {
         ShareParams.Builder shareParamsBuilder =
-                new ShareParams.Builder(window, title, getUrlToShare(visibleUrl));
+                new ShareParams.Builder(window, title, getUrlToShare(visibleUrl, mContext));
 
         shareParamsBuilder.setOrigin(shareOrigin);
-        boolean isDownloadedPdf = PdfUtils.isDownloadedPdf(visibleUrl.getSpec());
-        if (isDownloadedPdf) {
+        String decodedUrl = PdfUtils.decodePdfPageUrl(visibleUrl.getSpec());
+        Uri pdfUri = decodedUrl != null ? Uri.parse(decodedUrl) : null;
+        boolean isDownloadedPdf =
+                PdfUtils.isDownloadedPdf(visibleUrl.getSpec())
+                        && PdfUtils.isUriSafeForSharing(pdfUri, mContext);
+        if (isDownloadedPdf && pdfUri != null) {
             ArrayList<Uri> fileToShare = new ArrayList<>();
-            fileToShare.add(Uri.parse(PdfUtils.decodePdfPageUrl(visibleUrl.getSpec())));
+            fileToShare.add(pdfUri);
             shareParamsBuilder
                     .setFileUris(fileToShare)
                     .setFileContentType(MimeTypeUtils.PDF_MIME_TYPE);
@@ -285,8 +289,14 @@
     }
 
     @VisibleForTesting
-    static String getUrlToShare(GURL visibleUrl) {
-        if (PdfUtils.isDownloadedPdf(visibleUrl.getSpec())) return "";
+    static String getUrlToShare(GURL visibleUrl, @Nullable Context context) {
+        if (PdfUtils.isDownloadedPdf(visibleUrl.getSpec())) {
+            String decodedUrl = PdfUtils.decodePdfPageUrl(visibleUrl.getSpec());
+            Uri pdfUri = decodedUrl != null ? Uri.parse(decodedUrl) : null;
+            if (context == null || PdfUtils.isUriSafeForSharing(pdfUri, context)) {
+                return "";
+            }
+        }
         return visibleUrl.getSpec();
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/share/ShareDelegateImplTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/share/ShareDelegateImplTest.java
index a86b0aa..8294157e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/share/ShareDelegateImplTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/share/ShareDelegateImplTest.java
@@ -4,6 +4,9 @@
 
 package org.chromium.chrome.browser.share;
 
+import android.content.Context;
+
+import androidx.test.core.app.ApplicationProvider;
 import androidx.test.filters.SmallTest;
 
 import org.junit.Assert;
@@ -22,9 +25,10 @@
     @Test
     @SmallTest
     public void testGetUrlToShare() {
-        Assert.assertEquals("", ShareDelegateImpl.getUrlToShare(GURL.emptyGURL()));
+        Context context = ApplicationProvider.getApplicationContext();
+        Assert.assertEquals("", ShareDelegateImpl.getUrlToShare(GURL.emptyGURL(), context));
 
         final GURL httpsUrl = new GURL("https://blah.com");
-        Assert.assertEquals(httpsUrl.getSpec(), ShareDelegateImpl.getUrlToShare(httpsUrl));
+        Assert.assertEquals(httpsUrl.getSpec(), ShareDelegateImpl.getUrlToShare(httpsUrl, context));
     }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/share/ShareDelegateImplUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/share/ShareDelegateImplUnitTest.java
index 20dc99c3..06e6938a 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/share/ShareDelegateImplUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/share/ShareDelegateImplUnitTest.java
@@ -17,6 +17,8 @@
 
 import android.app.Activity;
 import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.ProviderInfo;
 import android.net.Uri;
 import android.os.Build;
 
@@ -61,6 +63,8 @@
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.components.browser_ui.share.ShareParams;
 import org.chromium.components.browser_ui.util.AutomotiveUtils;
+import org.chromium.components.dom_distiller.core.DomDistillerUrlUtils;
+import org.chromium.components.dom_distiller.core.DomDistillerUrlUtilsJni;
 import org.chromium.components.favicon.LargeIconBridgeJni;
 import org.chromium.components.feature_engagement.Tracker;
 import org.chromium.content_public.browser.RenderFrameHost;
@@ -87,6 +91,7 @@
             new OverrideContextWrapperTestRule();
 
     @Mock private Context mContext;
+    @Mock private PackageManager mPackageManager;
     @Mock private RenderFrameHost mRenderFrameHost;
     @Mock private BottomSheetController mBottomSheetController;
     @Mock private ShareSheetDelegate mShareSheetController;
@@ -105,6 +110,7 @@
     @Mock SnackbarManager mSnackbarManager;
 
     @Mock private DataProtectionBridge.Natives mDataProtectionBridgeMock;
+    @Mock private DomDistillerUrlUtils.Natives mDomDistillerUrlUtilsJniMock;
 
     private final ArgumentCaptor<ShareParams> mShareParamsCaptor =
             ArgumentCaptor.forClass(ShareParams.class);
@@ -166,6 +172,12 @@
         TrackerFactory.setTrackerForTests(mTracker);
         Mockito.doReturn(new WeakReference<>(mActivity)).when(mWindowAndroid).getActivity();
         DataProtectionBridge.setInstanceForTesting(mDataProtectionBridgeMock);
+        DomDistillerUrlUtilsJni.setInstanceForTesting(mDomDistillerUrlUtilsJniMock);
+        doAnswer(invocation -> new GURL((String) invocation.getArgument(0)))
+                .when(mDomDistillerUrlUtilsJniMock)
+                .getOriginalUrlFromDistillerUrl(anyString());
+        doReturn(mPackageManager).when(mContext).getPackageManager();
+        doReturn("org.chromium.chrome").when(mContext).getPackageName();
 
         // TODO(crbug.com/406591712): Update to stubbing share methods when those are added.
         doAnswer(sShareIsAllowedByPolicy)
@@ -735,4 +747,50 @@
                 "Page title should be set on ShareParams.", pdfTitle, params.getTitle());
         Assert.assertEquals("URL should be empty on ShareParams.", "", params.getUrl());
     }
+
+    @Test
+    public void testShareUnsafePDf() {
+        final String pdfTitle = "unsafe.pdf";
+        final String contentUri =
+                "content://org.chromium.chrome.FileProvider/passwords/ChromePass.csv";
+        final String pdfUrl = PdfUtils.encodePdfPageUrl(contentUri);
+        doReturn(true).when(mTab).isNativePage();
+        doReturn(new GURL(pdfUrl)).when(mTab).getUrl();
+        doReturn(pdfTitle).when(mTab).getTitle();
+        doReturn(mock(WindowAndroid.class)).when(mTab).getWindowAndroid();
+
+        // Setup mock package manager to identify this URI as coming from this app.
+        ProviderInfo providerInfo = new ProviderInfo();
+        providerInfo.packageName = "org.chromium.chrome";
+        doReturn(providerInfo)
+                .when(mPackageManager)
+                .resolveContentProvider("org.chromium.chrome.FileProvider", 0);
+
+        createShareDelegate(false, mShareSheetController);
+        mShareDelegate.share(mTab, false, ShareOrigin.OVERFLOW_MENU);
+        verify(mShareSheetController)
+                .share(
+                        mShareParamsCaptor.capture(),
+                        any(),
+                        any(),
+                        any(),
+                        any(),
+                        any(),
+                        any(),
+                        any(),
+                        any(),
+                        anyInt(),
+                        anyLong(),
+                        anyBoolean(),
+                        any(),
+                        any(),
+                        any(),
+                        any());
+
+        ShareParams params = mShareParamsCaptor.getValue();
+        // Should NOT be shared as file because it is unsafe.
+        Assert.assertNull("File URIs should be null for unsafe PDF.", params.getFileUris());
+        // Should be shared as URL instead.
+        Assert.assertEquals("URL should be the visible PDF URL.", pdfUrl, params.getUrl());
+    }
 }
Loading diff…

Original Bug Report

The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.