Chrome · WebAppInstalls
CVE-2026-14131
Logic Error in WebAppInstalls
Overview
Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
forchrome/browser/web_applications/jobs/manifest_to_web_app_install_info_job.cc |
modified | |
TEST_Fchrome/browser/web_applications/jobs/manifest_to_web_app_install_info_job_unittest.cc |
modified |
Files Changed
chrome/browser/web_applications/isolated_web_apps/manifest_update_unittest.ccchrome/browser/web_applications/jobs/manifest_to_web_app_install_info_job.ccchrome/browser/web_applications/jobs/manifest_to_web_app_install_info_job_unittest.cc
Patch
From 83acaeae804d4ad86a71a6e5e786cdd51c327951 Mon Sep 17 00:00:00 2001
From: Edman Anjos <edmanp@google.com>
Date: Mon, 01 Jun 2026 10:56:39 -0700
Subject: [PATCH] Ignore unframed display override in install job when the flag is disabled
Fixed: 514020982
Test: testing/xvfb.py tools/autotest.py -C out_/Default chrome/browser/web_applications/jobs/manifest_to_web_app_install_info_job_unittest.cc chrome/browser/web_applications/isolated_web_apps/manifest_update_unittest.cc
Change-Id: I86539fe197f2ffb7d9e4fb991190b88ad73ab90a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7867923
Reviewed-by: Eshwar Stalin <estalin@chromium.org>
Commit-Queue: Edman Anjos <edman@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1639520}
---
diff --git a/chrome/browser/web_applications/isolated_web_apps/manifest_update_unittest.cc b/chrome/browser/web_applications/isolated_web_apps/manifest_update_unittest.cc
index 4fbb5184..5fb9b5c 100644
--- a/chrome/browser/web_applications/isolated_web_apps/manifest_update_unittest.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/manifest_update_unittest.cc
@@ -3,10 +3,13 @@
// found in the LICENSE file.
#include <memory>
+#include <optional>
#include <string_view>
#include <vector>
+#include "base/auto_reset.h"
#include "base/check_deref.h"
+#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
#include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.h"
@@ -32,6 +35,7 @@
#include "components/webapps/isolated_web_apps/types/update_channel.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/safe_url_pattern.h"
#include "third_party/liburlpattern/part.h"
@@ -100,6 +104,7 @@
public:
ManifestUpdateTest()
: IsolatedWebAppTest(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {
+ scoped_feature_list_.InitAndEnableFeature(blink::features::kUnframedIwa);
}
~ManifestUpdateTest() override = default;
@@ -162,6 +167,7 @@
ASSERT_THAT(TestIwa(), HasVersion("2.0.0"));
}
+ base::test::ScopedFeatureList scoped_feature_list_;
FakeIwaRuntimeDataProvider data_provider_;
std::optional<base::AutoReset<ChromeIwaRuntimeDataProvider*>> resetter_;
};
diff --git a/chrome/browser/web_applications/jobs/manifest_to_web_app_install_info_job.cc b/chrome/browser/web_applications/jobs/manifest_to_web_app_install_info_job.cc
index 1e64842..5744abc0 100644
--- a/chrome/browser/web_applications/jobs/manifest_to_web_app_install_info_job.cc
+++ b/chrome/browser/web_applications/jobs/manifest_to_web_app_install_info_job.cc
@@ -813,10 +813,15 @@
install_info().display_mode = manifest_->display;
}
for (const auto& override_item : manifest_->display_override) {
- install_info().display_override.push_back(
- override_item.display() == DisplayMode::kUnframed
- ? DisplayOverride::CreateUnframed(override_item.url_patterns())
- : DisplayOverride::Create(override_item.display()));
+ if (override_item.display() == DisplayMode::kUnframed) {
+ if (base::FeatureList::IsEnabled(blink::features::kUnframedIwa)) {
+ install_info().display_override.push_back(
+ DisplayOverride::CreateUnframed(override_item.url_patterns()));
+ }
+ } else {
+ install_info().display_override.push_back(
+ DisplayOverride::Create(override_item.display()));
+ }
}
const std::vector<blink::Manifest::ImageResource>& icons =
diff --git a/chrome/browser/web_applications/jobs/manifest_to_web_app_install_info_job_unittest.cc b/chrome/browser/web_applications/jobs/manifest_to_web_app_install_info_job_unittest.cc
index b0c0cce..fef5eb6 100644
--- a/chrome/browser/web_applications/jobs/manifest_to_web_app_install_info_job_unittest.cc
+++ b/chrome/browser/web_applications/jobs/manifest_to_web_app_install_info_job_unittest.cc
@@ -12,6 +12,7 @@
#include <utility>
#include <vector>
+#include "base/feature_list.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind.h"
@@ -167,7 +168,8 @@
TEST_F(ManifestToWebAppInstallInfoJobTest, BasicFieldsPopulated) {
base::test::ScopedFeatureList feature_list;
feature_list.InitWithFeatures({blink::features::kFileHandlingIcons,
- blink::features::kWebAppManifestLockScreen},
+ blink::features::kWebAppManifestLockScreen,
+ blink::features::kUnframedIwa},
/*disabled_features=*/{});
SetupBasicPageState();
@@ -2213,6 +2215,37 @@
EXPECT_EQ(default_icon_url, icons[0].url);
}
+TEST_F(ManifestToWebAppInstallInfoJobTest,
+ AcceptsUnframedDisplayOverrideWhenTheFeatureIsEnabled) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(blink::features::kUnframedIwa);
+
+ ASSERT_TRUE(base::FeatureList::IsEnabled(blink::features::kUnframedIwa));
+
+ SetupBasicPageState();
+ blink::mojom::ManifestPtr& manifest = GetPageManifest();
+ manifest->display_override.push_back(
+ blink::Manifest::DisplayOverride::CreateUnframed({FooUrlPattern()}));
+
+ auto web_app_info = GetWebAppInstallInfoFromJob(*manifest);
+ EXPECT_THAT(
+ web_app_info->display_override,
+ testing::ElementsAre(DisplayOverride::CreateUnframed({FooUrlPattern()})));
+}
+
+TEST_F(ManifestToWebAppInstallInfoJobTest,
+ IgnoresUnframedDisplayOverrideWhenTheFeatureIsDisabled) {
+ ASSERT_FALSE(base::FeatureList::IsEnabled(blink::features::kUnframedIwa));
+
+ SetupBasicPageState();
+ blink::mojom::ManifestPtr& manifest = GetPageManifest();
+ manifest->display_override.push_back(
+ blink::Manifest::DisplayOverride::CreateUnframed());
+
+ auto web_app_info = GetWebAppInstallInfoFromJob(*manifest);
+ EXPECT_THAT(web_app_info->display_override, testing::IsEmpty());
+}
+
} // namespace
} // namespace web_app
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/chrome/browser/web_applications/isolated_web_apps/manifest_update_unittest.cc b/chrome/browser/web_applications/isolated_web_apps/manifest_update_unittest.cc
index 4fbb5184..5fb9b5c 100644
--- a/chrome/browser/web_applications/isolated_web_apps/manifest_update_unittest.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/manifest_update_unittest.cc
@@ -3,10 +3,13 @@
// found in the LICENSE file.
#include <memory>
+#include <optional>
#include <string_view>
#include <vector>
+#include "base/auto_reset.h"
#include "base/check_deref.h"
+#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
#include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.h"
@@ -32,6 +35,7 @@
#include "components/webapps/isolated_web_apps/types/update_channel.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/safe_url_pattern.h"
#include "third_party/liburlpattern/part.h"
@@ -100,6 +104,7 @@
public:
ManifestUpdateTest()
: IsolatedWebAppTest(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {
+ scoped_feature_list_.InitAndEnableFeature(blink::features::kUnframedIwa);
}
~ManifestUpdateTest() override = default;
@@ -162,6 +167,7 @@
ASSERT_THAT(TestIwa(), HasVersion("2.0.0"));
}
+ base::test::ScopedFeatureList scoped_feature_list_;
FakeIwaRuntimeDataProvider data_provider_;
std::optional<base::AutoReset<ChromeIwaRuntimeDataProvider*>> resetter_;
};
diff --git a/chrome/browser/web_applications/jobs/manifest_to_web_app_install_info_job_unittest.cc b/chrome/browser/web_applications/jobs/manifest_to_web_app_install_info_job_unittest.cc
index b0c0cce..fef5eb6 100644
--- a/chrome/browser/web_applications/jobs/manifest_to_web_app_install_info_job_unittest.cc
+++ b/chrome/browser/web_applications/jobs/manifest_to_web_app_install_info_job_unittest.cc
@@ -12,6 +12,7 @@
#include <utility>
#include <vector>
+#include "base/feature_list.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind.h"
@@ -167,7 +168,8 @@
TEST_F(ManifestToWebAppInstallInfoJobTest, BasicFieldsPopulated) {
base::test::ScopedFeatureList feature_list;
feature_list.InitWithFeatures({blink::features::kFileHandlingIcons,
- blink::features::kWebAppManifestLockScreen},
+ blink::features::kWebAppManifestLockScreen,
+ blink::features::kUnframedIwa},
/*disabled_features=*/{});
SetupBasicPageState();
@@ -2213,6 +2215,37 @@
EXPECT_EQ(default_icon_url, icons[0].url);
}
+TEST_F(ManifestToWebAppInstallInfoJobTest,
+ AcceptsUnframedDisplayOverrideWhenTheFeatureIsEnabled) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(blink::features::kUnframedIwa);
+
+ ASSERT_TRUE(base::FeatureList::IsEnabled(blink::features::kUnframedIwa));
+
+ SetupBasicPageState();
+ blink::mojom::ManifestPtr& manifest = GetPageManifest();
+ manifest->display_override.push_back(
+ blink::Manifest::DisplayOverride::CreateUnframed({FooUrlPattern()}));
+
+ auto web_app_info = GetWebAppInstallInfoFromJob(*manifest);
+ EXPECT_THAT(
+ web_app_info->display_override,
+ testing::ElementsAre(DisplayOverride::CreateUnframed({FooUrlPattern()})));
+}
+
+TEST_F(ManifestToWebAppInstallInfoJobTest,
+ IgnoresUnframedDisplayOverrideWhenTheFeatureIsDisabled) {
+ ASSERT_FALSE(base::FeatureList::IsEnabled(blink::features::kUnframedIwa));
+
+ SetupBasicPageState();
+ blink::mojom::ManifestPtr& manifest = GetPageManifest();
+ manifest->display_override.push_back(
+ blink::Manifest::DisplayOverride::CreateUnframed());
+
+ auto web_app_info = GetWebAppInstallInfoFromJob(*manifest);
+ EXPECT_THAT(web_app_info->display_override, testing::IsEmpty());
+}
+
} // namespace
} // namespace web_app
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.
References
On This Page