diff --git a/components/password_manager/content/browser/content_password_manager_driver.cc b/components/password_manager/content/browser/content_password_manager_driver.cc index 28f7beb14e7af..3cf254f02c52a 100644 --- a/components/password_manager/content/browser/content_password_manager_driver.cc +++ b/components/password_manager/content/browser/content_password_manager_driver.cc @@ -208,8 +208,27 @@ void ContentPasswordManagerDriver::PropagateFillDataOnParsingCompletion( password_autofill_manager_.OnAddPasswordFillData(form_data); } if (const auto& agent = GetPasswordAutofillAgent()) { + // Defense in depth: the kCrossOriginIframe gate in + // SendFillInformationToRenderer() compares only the primary main frame + // against this frame. Walk the full ancestor chain here so a same-origin + // subframe sandwiched under a cross-origin intermediate ancestor never + // receives cleartext password values over IPC. This brings the + // browser-side gate to parity with the renderer-side + // IsInCrossOriginIframeOrEmbeddedFrame() check. + autofill::PasswordFormFillData to_send = form_data; + if (!to_send.wait_for_username) { + const url::Origin& target = render_frame_host_->GetLastCommittedOrigin(); + for (content::RenderFrameHost* ancestor = + render_frame_host_->GetParentOrOuterDocument(); + ancestor; ancestor = ancestor->GetParentOrOuterDocument()) { + if (!target.IsSameOriginWith(ancestor->GetLastCommittedOrigin())) { + to_send.wait_for_username = true; + break; + } + } + } agent->ApplyFillDataOnParsingCompletion( - autofill::MaybeClearPasswordValues(form_data)); + autofill::MaybeClearPasswordValues(to_send)); } }