Overview

Low
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInappropriate implementation in DevTools
DescriptionInappropriate implementation in DevTools
ComponentDevTools
Bug ClassLogic Error
Tracker401927528
Fix commita702323c7c0f (devtools/devtools-frontend) +68/-4
CISA KEVNot listed
Creditedvanillawebdev
Disclosed2025-04-29

Changed Functions

FunctionChangeNotes
constructor
front_end/panels/recorder/RecorderController.ts
modified
if
front_end/panels/recorder/RecorderController.ts
modified

Files Changed

  • front_end/panels/recorder/BUILD.gn
  • front_end/panels/recorder/RecorderController.ts
  • front_end/ui/visual_logging/KnownContextValues.ts
From a702323c7c0f226bd02c3971de19f9bbc98a4de1 Mon Sep 17 00:00:00 2001
From: Alex Rudenko <[email protected]>
Date: Fri, 14 Mar 2025 09:15:20 +0100
Subject: [PATCH] [Recorder] Confirm recording import the first time

Uses the same pattern that is used to confirm pasting.

Fixed: 402071098
Bug: 401927528
Change-Id: I1317fa81bff3cb5a17e4923596e10af05350fb82
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/6343138
Commit-Queue: Alex Rudenko <[email protected]>
Reviewed-by: Wolfgang Beyer <[email protected]>
---

diff --git a/front_end/panels/recorder/BUILD.gn b/front_end/panels/recorder/BUILD.gn
index bcb4e17..765fd2d 100644
--- a/front_end/panels/recorder/BUILD.gn
+++ b/front_end/panels/recorder/BUILD.gn
@@ -21,8 +21,10 @@
   deps = [
     "../../core/common:bundle",
     "../../core/platform:bundle",
+    "../../core/root:bundle",
     "../../models/extensions:bundle",
     "../../models/trace:bundle",
+    "../../panels/common:bundle",
     "../../panels/emulation:bundle",
     "../../panels/timeline:bundle",
     "../../services/tracing:bundle",
diff --git a/front_end/panels/recorder/RecorderController.ts b/front_end/panels/recorder/RecorderController.ts
index 662270b..3909bf9 100644
--- a/front_end/panels/recorder/RecorderController.ts
+++ b/front_end/panels/recorder/RecorderController.ts
@@ -6,10 +6,12 @@
 import * as Host from '../../core/host/host.js';
 import * as i18n from '../../core/i18n/i18n.js';
 import * as Platform from '../../core/platform/platform.js';
+import * as Root from '../../core/root/root.js';
 import * as SDK from '../../core/sdk/sdk.js';
 import * as Bindings from '../../models/bindings/bindings.js';
 import * as PublicExtensions from '../../models/extensions/extensions.js';
 import type * as Trace from '../../models/trace/trace.js';
+import * as PanelCommon from '../../panels/common/common.js';
 import * as Emulation from '../../panels/emulation/emulation.js';
 import * as Timeline from '../../panels/timeline/timeline.js';
 import * as Tracing from '../../services/tracing/tracing.js';
@@ -119,7 +121,27 @@
   /**
    * @description Link text to forward to a documentation page on the recorder.
    */
-  learnMore: 'Learn more'
+  learnMore: 'Learn more',
+  /**
+   *@description Headline of warning shown to users when users import a recording into DevTools Recorder.
+   */
+  doYouTrustThisCode: 'Do you trust this recording?',
+  /**
+   *@description Warning shown to users when imports code into DevTools Recorder.
+   *@example {allow importing} PH1
+   */
+  doNotImport:
+      'Don\'t import recordings you do not understand or have not reviewed yourself into DevTools. This could allow attackers to steal your identity or take control of your computer. Please type \'\'{PH1}\'\' below to allow importing.',
+  /**
+   *@description Text a user needs to type in order to confirm that they
+   *are aware of the danger of import code into the DevTools Recorder.
+   */
+  allowImporting: 'allow importing',
+  /**
+   *@description Input box placeholder which instructs the user to type 'allow pasing' into the input box.
+   *@example {allow importing} PH1
+   */
+  typeAllowImporting: 'Type \'\'{PH1}\'\'',
 } as const;
 const str_ = i18n.i18n.registerUIStrings('panels/recorder/RecorderController.ts', UIStrings);
 const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
@@ -224,6 +246,11 @@
   #recorderSettings = new Models.RecorderSettings.RecorderSettings();
   #shortcutHelper = new Models.RecorderShortcutHelper.RecorderShortcutHelper();
 
+  #disableRecorderImportWarningSetting = Common.Settings.Settings.instance().createSetting(
+      'disable-recorder-import-warning', false, Common.Settings.SettingStorageType.SYNCED);
+  #selfXssWarningDisabledSetting = Common.Settings.Settings.instance().createSetting(
+      'disable-self-xss-warning', false, Common.Settings.SettingStorageType.SYNCED);
+
   constructor() {
     super();
 
@@ -967,11 +994,43 @@
         ?.click();
   }
 
-  #onImportRecording(event: Event): void {
+  async #acknowledgeImportNotice(): Promise<boolean> {
+    if (this.#disableRecorderImportWarningSetting.get()) {
+      return true;
+    }
+
+    if (Root.Runtime.Runtime.queryParam('isChromeForTesting') ||
+        Root.Runtime.Runtime.queryParam('disableSelfXssWarnings') || this.#selfXssWarningDisabledSetting.get()) {
+      return true;
+    }
+
+    const result = await PanelCommon.TypeToAllowDialog.show({
+      jslogContext: {
+        input: 'confirm-import-recording-input',
+        dialog: 'confirm-import-recording-dialog',
+      },
+      message: i18nString(UIStrings.doNotImport, {PH1: i18nString(UIStrings.allowImporting)}),
+      header: i18nString(UIStrings.doYouTrustThisCode),
+      typePhrase: i18nString(UIStrings.allowImporting),
+      inputPlaceholder: i18nString(UIStrings.typeAllowImporting, {PH1: i18nString(UIStrings.allowImporting)}),
+    });
+
+    if (result) {
+      this.#disableRecorderImportWarningSetting.set(true);
+    }
+
+    return result;
+  }
+
+  async #onImportRecording(event: Event): Promise<void> {
     event.stopPropagation();
+
     this.#clearError();
-    this.#fileSelector = UI.UIUtils.createFileSelectorElement(this.#importFile.bind(this));
-    this.#fileSelector.click();
+
+    if (await this.#acknowledgeImportNotice()) {
+      this.#fileSelector = UI.UIUtils.createFileSelectorElement(this.#importFile.bind(this));
+      this.#fileSelector.click();
+    }
   }
 
   async #onPlayRecordingByName(event: Components.RecordingListView.PlayRecordingEvent): Promise<void> {
diff --git a/front_end/ui/visual_logging/KnownContextValues.ts b/front_end/ui/visual_logging/KnownContextValues.ts
index 17642a6..010ea25 100644
--- a/front_end/ui/visual_logging/KnownContextValues.ts
+++ b/front_end/ui/visual_logging/KnownContextValues.ts
@@ -791,6 +791,8 @@
   'conditional-breakpoint',
   'configure',
   'confirm',
+  'confirm-import-recording-dialog',
+  'confirm-import-recording-input',
   'connection',
   'connection-id',
   'consent-onboarding',
@@ -1196,6 +1198,7 @@
   'disable-file-breakpoints',
   'disable-locale-info-bar',
   'disable-paused-state-overlay',
+  'disable-recorder-import-warning',
   'disable-self-xss-warning',
   'disabled',
   'disallowed-select-descendants-details',
Loading diff…

Original Bug Report

reported by [email protected]

DevTools Recorder Can Flip Internal Flags Without User Awareness

Security Bug

Important: Please do not change the component of this bug manually.

Please READ THIS FAQ before filing a bug: https://chromium.googlesource.com/chromium/src/+/HEAD/docs/security/faq.md

Please see the following link for instructions on filing security bugs: https://www.chromium.org/Home/chromium-security/reporting-security-bugs

Reports may be eligible for reward payments under the Chrome VRP: https://g.co/chrome/vrp

NOTE: Security bugs are normally made public once a fix has been widely deployed.


VULNERABILITY DETAILS

Chrome DevTools Recorder currently allows regular users to automate steps on chrome:// URLs. This opens the door for social engineering attacks, where users can be tricked into executing pre-recorded scripts that flips flags without clear user consent.

This issue also bleeds to ChromeOS where extensions requires explicit permission to allow injecting script in chrome://file-manager/* URLs, which is currently disabled by default. By flipping a certain flag (#extensions-on-chrome-urls), the attacker could start another system attack.

VERSION

Tested in: Chrome Version: 134.0.6998.36 (Official Build) (64-bit) Operating System: Windows NT: 10.0.19044

REPRODUCTION CASE

I’ve attached an HTML page that looks like a valid tutorial on enabling 60FPS for web mobile games. It guides users to download and run a DevTools Recorder script that flips #extensions-on-chrome-urls flag without their full awareness. Follow the guide in the HTML file:

  1. Download attached HTML file.
  2. Download the recorder script provided in the tutorial page.
  3. Import the and replay the recorder file in DevTools Recorder.

Since the chrome://flags can automatically jump to certain flags, this makes the victim unaware that the target flag has been flipped. Furthermore, the warning at the very top of the page is not visible upon Relaunch as seen in the video

In this particular example, the flag is used to allows chrome extensions to run in chrome:// URLs.

SUGGESTED SOLUTION

To perform recorder steps in chrome://* URLs, the user should explicitly enable a flag in chrome://flags.

CREDIT INFORMATION

Externally reported security bugs may appear in Chrome release notes. If this bug is included, how would you like to be credited? Reporter credit: vanillawebdev

View on issue tracker