tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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:
Mbrowser/components/tabbrowser/content/tabbrowser.js | 6++++++
Mbrowser/components/tabbrowser/test/browser/tabs/browser.toml | 3+++
Abrowser/components/tabbrowser/test/browser/tabs/browser_tab_label_character_cap.js | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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" + ); + }); +});