diff --git a/chrome/browser/webshare/share_service_impl.cc b/chrome/browser/webshare/share_service_impl.cc index 1d41ae3de52c7..0a18b61ace1e7 100644 --- a/chrome/browser/webshare/share_service_impl.cc +++ b/chrome/browser/webshare/share_service_impl.cc @@ -190,6 +190,18 @@ void ShareServiceImpl::Share(const std::string& title, return; } + // Defense-in-depth: the renderer is supposed to restrict |share_url| to + // http(s) or the document's own scheme (NOT its -derived base URL). + // Re-validate here so a compromised or buggy renderer cannot ship file:/ + // chrome:/filesystem: URLs to the OS share sheet. + if (!share_url.is_empty() && !share_url.SchemeIsHTTPOrHTTPS() && + share_url.scheme() != + render_frame_host().GetLastCommittedURL().scheme()) { + std::move(callback).Run(blink::mojom::ShareError::PERMISSION_DENIED); + ReportBadMessageAndDeleteThis("Disallowed share_url scheme"); + return; + } + if (files.size() > kMaxSharedFileCount) { VLOG(1) << "Share too large: " << files.size() << " files"; std::move(callback).Run(blink::mojom::ShareError::PERMISSION_DENIED); diff --git a/third_party/blink/renderer/modules/webshare/navigator_share.cc b/third_party/blink/renderer/modules/webshare/navigator_share.cc index 71d8b47de2d03..6ee9767bdeca3 100644 --- a/third_party/blink/renderer/modules/webshare/navigator_share.cc +++ b/third_party/blink/renderer/modules/webshare/navigator_share.cc @@ -92,9 +92,13 @@ bool CanShareInternal(const LocalDOMWindow& window, if (data.hasUrl()) { url = window.CompleteURL(data.url()); + // Compare against the document's own URL scheme, not BaseURL(): the latter + // is derived from and is fully attacker-controlled, so an + // https page could set and share file:/chrome: + // URLs. if (!url.IsValid() || (!url.ProtocolIsInHttpFamily() && - url.Protocol() != window.document()->BaseURL().Protocol())) { + url.Protocol() != window.Url().Protocol())) { if (exception_state) { exception_state->ThrowTypeError("Invalid URL"); }