Chrome · Chrome for iOS
CVE-2026-17913
Logic Error in Chrome for iOS
Overview
Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
AnnotationTextManagerTestios/web/annotations/annotations_java_script_feature.h |
modified | |
AnnotationsJavaScriptFeatureios/web/annotations/annotations_java_script_feature.h |
modified | |
GetAnnotationsReplacementsios/web/annotations/annotations_java_script_feature.mm |
modified | |
trusted_event_check_enabled_ios/web/annotations/annotations_java_script_feature.mm |
modified | |
ifios/web/annotations/annotations_java_script_feature.mm |
modified | |
forios/web/annotations/annotations_java_script_feature.mm |
modified | |
switchios/web/annotations/resources/text_click.ts |
modified | |
MutationsTrackerios/web/annotations/resources/text_click.ts |
modified |
Files Changed
ios/web/annotations/annotations_inttest.mmios/web/annotations/annotations_java_script_feature.hios/web/annotations/annotations_java_script_feature.mmios/web/annotations/resources/text_click.ts
Patch
From 48a2dca4b7094b466a37d18dc09113485466b99c Mon Sep 17 00:00:00 2001
From: Olivier ROBIN <olivierrobin@google.com>
Date: Tue, 09 Jun 2026 07:09:35 -0700
Subject: [PATCH] Check isTrusted for annotations events
Only allow trusted event to trigger native UI on annotations.
Fixed: 504209246
Change-Id: I9c2dd404cdbe4236d64f34a8a0992e6cb1daf5e7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7885878
Commit-Queue: Olivier Robin <olivierrobin@chromium.org>
Auto-Submit: Olivier Robin <olivierrobin@chromium.org>
Reviewed-by: Mike Dougherty <michaeldo@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1643932}
---
diff --git a/ios/web/annotations/annotations_inttest.mm b/ios/web/annotations/annotations_inttest.mm
index 6fabc5c..fb5b310 100644
--- a/ios/web/annotations/annotations_inttest.mm
+++ b/ios/web/annotations/annotations_inttest.mm
@@ -149,6 +149,11 @@
protected:
void SetUp() override {
+ override_feature_ = base::WrapUnique(new AnnotationsJavaScriptFeature(
+ /*trusted_event_check_enabled=*/false));
+ AnnotationsJavaScriptFeature::SetInstanceForTesting(
+ override_feature_.get());
+
WebTestWithWebState::SetUp();
AnnotationsTextManager::CreateForWebState(web_state());
@@ -175,6 +180,8 @@
auto* manager = AnnotationsTextManager::FromWebState(web_state());
manager->RemoveObserver(&observer_);
WebTestWithWebState::TearDown();
+
+ AnnotationsJavaScriptFeature::SetInstanceForTesting(nullptr);
}
virtual std::string GetScriptName() { return ""; }
@@ -320,6 +327,7 @@
TestAnnotationTextObserver* observer() { return &observer_; }
+ std::unique_ptr<AnnotationsJavaScriptFeature> override_feature_;
base::test::ScopedFeatureList feature_;
raw_ptr<JavaScriptContentWorld> content_world_;
TestAnnotationTextObserver observer_;
diff --git a/ios/web/annotations/annotations_java_script_feature.h b/ios/web/annotations/annotations_java_script_feature.h
index 74464d9..b9c02773 100644
--- a/ios/web/annotations/annotations_java_script_feature.h
+++ b/ios/web/annotations/annotations_java_script_feature.h
@@ -14,6 +14,8 @@
namespace web {
+class AnnotationTextManagerTest;
+
extern const int kMaxAnnotationsTextLength;
extern const int kMaxAnnotationsMetadataLength;
@@ -23,6 +25,9 @@
class AnnotationsJavaScriptFeature : public JavaScriptFeature {
public:
static AnnotationsJavaScriptFeature* GetInstance();
+ static void SetInstanceForTesting(AnnotationsJavaScriptFeature* instance);
+
+ ~AnnotationsJavaScriptFeature() override;
// Triggers the JS text extraction code. Async calls `OnTextExtracted` on
// `AnnotationsTextManager` when done using provided `seq_id`.
@@ -49,14 +54,19 @@
const ScriptMessage& script_message) override;
std::optional<std::string> GetScriptMessageHandlerName() const override;
AnnotationsJavaScriptFeature();
- ~AnnotationsJavaScriptFeature() override;
private:
friend class base::NoDestructor<AnnotationsJavaScriptFeature>;
+ friend class AnnotationTextManagerTest;
+
+ // Constructor that allows disabling trusted event checks, e.g. for testing.
+ explicit AnnotationsJavaScriptFeature(bool trusted_event_check_enabled);
AnnotationsJavaScriptFeature(const AnnotationsJavaScriptFeature&) = delete;
AnnotationsJavaScriptFeature& operator=(const AnnotationsJavaScriptFeature&) =
delete;
+
+ bool trusted_event_check_enabled_ = true;
};
} // namespace web
diff --git a/ios/web/annotations/annotations_java_script_feature.mm b/ios/web/annotations/annotations_java_script_feature.mm
index e4f8c729..100e8578 100644
--- a/ios/web/annotations/annotations_java_script_feature.mm
+++ b/ios/web/annotations/annotations_java_script_feature.mm
@@ -20,6 +20,16 @@
namespace {
const char kScriptName[] = "text_main";
const char kScriptHandlerName[] = "annotations";
+
+web::AnnotationsJavaScriptFeature* g_instance_for_testing = nullptr;
+
+web::JavaScriptFeature::FeatureScript::PlaceholderReplacements
+GetAnnotationsReplacements(bool trusted_event_check_enabled) {
+ return @{
+ @"{{SkipTrustedCheckForTesting}}" : trusted_event_check_enabled ? @"false"
+ : @"true"
+ };
+}
} // namespace
namespace web {
@@ -28,22 +38,38 @@
const int kMaxAnnotationsMetadataLength = 256;
AnnotationsJavaScriptFeature::AnnotationsJavaScriptFeature()
+ : AnnotationsJavaScriptFeature(true) {}
+
+AnnotationsJavaScriptFeature::AnnotationsJavaScriptFeature(
+ bool trusted_event_check_enabled)
: JavaScriptFeature(
ContentWorld::kIsolatedWorld,
{FeatureScript::CreateWithFilename(
kScriptName,
FeatureScript::InjectionTime::kDocumentStart,
FeatureScript::TargetFrames::kMainFrame,
- FeatureScript::ReinjectionBehavior::kInjectOncePerWindow)}) {}
+ FeatureScript::ReinjectionBehavior::kInjectOncePerWindow,
+ base::BindRepeating(&GetAnnotationsReplacements,
+ trusted_event_check_enabled))}),
+ trusted_event_check_enabled_(trusted_event_check_enabled) {}
AnnotationsJavaScriptFeature::~AnnotationsJavaScriptFeature() = default;
// static
AnnotationsJavaScriptFeature* AnnotationsJavaScriptFeature::GetInstance() {
+ if (g_instance_for_testing) {
+ return g_instance_for_testing;
+ }
static base::NoDestructor<AnnotationsJavaScriptFeature> instance;
return instance.get();
}
+// static
+void AnnotationsJavaScriptFeature::SetInstanceForTesting(
+ AnnotationsJavaScriptFeature* instance) {
+ g_instance_for_testing = instance;
+}
+
void AnnotationsJavaScriptFeature::ExtractText(WebState* web_state,
int maximum_text_length,
int seq_id) {
@@ -191,6 +217,9 @@
manager->OnDecorated(web_state, annotations, successes, failures,
*cancelled);
} else if (*command == "annotations.onClick") {
+ if (trusted_event_check_enabled_ && !script_message.is_user_interacting()) {
+ return;
+ }
for (const auto pair : dict) {
const std::string& key = pair.first;
if (key != "command" && key != "data" && key != "rect" && key != "text" &&
diff --git a/ios/web/annotations/resources/text_click.ts b/ios/web/annotations/resources/text_click.ts
index 738889f..1dbf985 100644
--- a/ios/web/annotations/resources/text_click.ts
+++ b/ios/web/annotations/resources/text_click.ts
@@ -18,6 +18,20 @@
// Delay while checking for DOM mutations.
export const DOM_MUTATION_DELAY_MS = 300;
+/**
+ * Parses a string to a boolean.
+ * @param boolStr The string to parse as a boolean.
+ * @returns The boolean value.
+ */
+function stringAsBool(boolStr: string): boolean {
+ switch (boolStr) {
+ case 'true':
+ return true;
+ default:
+ return false;
+ }
+}
+
// Monitors DOM mutations between instance construction until a call to
// `stopObserving`.
class MutationsTracker {
@@ -97,7 +111,9 @@
private decorationsProvider: () => Map<number, TextDecoration>| undefined,
private taskTimer: TaskTimer = new LiveTaskTimer(),
private mutationCheckDelay = DOM_MUTATION_DELAY_MS,
- private annotationForTest: Element|null = null) {}
+ private annotationForTest: Element|null = null,
+ private skipTrustedCheckForTesting =
+ stringAsBool('{{SkipTrustedCheckForTesting}}')) {}
// Starts event listeners.
start(): void {
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