commit b8f0363af1bc67c50e661a675bf4fb3cf2d99fce
parent d83a2bf4418983265a1e9a439679af12186447d1
Author: Jared Wein <jwein@mozilla.com>
Date: Fri, 21 Nov 2025 18:21:17 +0000
Bug 736194 - Clamp tab title length to a reasonable number to prevent hangs r=tabbrowser-reviewers,nsharpley,dao
Differential Revision: https://phabricator.services.mozilla.com/D273431
Diffstat:
3 files changed, 67 insertions(+), 0 deletions(-)
diff --git a/browser/components/tabbrowser/content/tabbrowser.js b/browser/components/tabbrowser/content/tabbrowser.js
@@ -30,6 +30,7 @@
const DIRECTION_FORWARD = 1;
const DIRECTION_BACKWARD = -1;
+ const TAB_LABEL_MAX_LENGTH = 256;
/**
* Updates the User Context UI indicators if the browser is in a non-default context
@@ -1981,6 +1982,11 @@
aLabel = aLabel.replace(this._regex_shortenURLForTabLabel, "");
}
+ if (aLabel.length > TAB_LABEL_MAX_LENGTH) {
+ // Clamp overly-long titles to avoid DoS-type hangs (bug 736194).
+ aLabel = aLabel.substring(0, TAB_LABEL_MAX_LENGTH);
+ }
+
aTab._labelIsContentTitle = isContentTitle;
if (aTab.getAttribute("label") == aLabel) {
diff --git a/browser/components/tabbrowser/test/browser/tabs/browser.toml b/browser/components/tabbrowser/test/browser/tabs/browser.toml
@@ -183,6 +183,9 @@ skip-if = [
["browser_long_data_url_label_truncation.js"]
tags = "vertical-tabs"
+["browser_tab_label_character_cap.js"]
+tags = "vertical-tabs"
+
["browser_middle_click_new_tab_button_loads_clipboard.js"]
tags = "vertical-tabs"
fail-if = ["vertical_tab"] # Bug 1932787, fails in the "vertical-tabs" variant
diff --git a/browser/components/tabbrowser/test/browser/tabs/browser_tab_label_character_cap.js b/browser/components/tabbrowser/test/browser/tabs/browser_tab_label_character_cap.js
@@ -0,0 +1,58 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/**
+ * Ensure that setTabTitle clamps very long document titles to 255 characters
+ * so malicious pages cannot hang the browser by forcing us to lay out absurdly
+ * large tab labels.
+ */
+add_task(async function test_tab_label_is_capped_at_255_chars() {
+ const LONG_TITLE_LENGTH = 257;
+ const EXPECTED_LABEL_LENGTH = 256;
+ const TITLE_CHAR = "A";
+
+ await BrowserTestUtils.withNewTab("about:blank", async browser => {
+ const tab = gBrowser.getTabForBrowser(browser);
+
+ const fullTitleLength = await SpecialPowers.spawn(
+ browser,
+ [LONG_TITLE_LENGTH, TITLE_CHAR],
+ (length, character) => {
+ content.document.title = character.repeat(length);
+ return content.document.title.length;
+ }
+ );
+ Assert.equal(
+ fullTitleLength,
+ LONG_TITLE_LENGTH,
+ "Sanity check: content received the full title"
+ );
+
+ await BrowserTestUtils.waitForCondition(
+ () => tab.label.length === EXPECTED_LABEL_LENGTH,
+ "Tab label should be clamped"
+ );
+
+ Assert.equal(
+ tab.label.length,
+ EXPECTED_LABEL_LENGTH,
+ "Displayed label is capped at 256 characters"
+ );
+ Assert.equal(
+ tab.label,
+ TITLE_CHAR.repeat(EXPECTED_LABEL_LENGTH),
+ "Tab label matches the first 256 title characters"
+ );
+
+ const reportedTitleLength = await SpecialPowers.spawn(browser, [], () => {
+ return content.document.title.length;
+ });
+ Assert.equal(
+ reportedTitleLength,
+ LONG_TITLE_LENGTH,
+ "document.title remains unchanged"
+ );
+ });
+});