Low firefox Logic Error 🔧 Commit mapped

Overview

Low
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
Impactlow
DescriptionSpoofing issue in the Web Speech component
ComponentDOM
Bug ClassLogic Error
Tracker2021222
Fix commit8b5820a0b4a2 (firefox) +65/-0
CISA KEVNot listed
CreditedQadhafy Muhammad Tera
Disclosed2026-05-19

Changed Functions

FunctionChangeNotes
function
dom/media/webspeech/synth/test/test_speech_cancel_on_navigation.html
modified

Files Changed

  • dom/media/webspeech/synth/SpeechSynthesis.cpp
  • dom/media/webspeech/synth/SpeechSynthesis.h
  • dom/media/webspeech/synth/test/file_speech_cancel_on_navigation_page1.html
  • dom/media/webspeech/synth/test/file_speech_cancel_on_navigation_page2.html
  • dom/media/webspeech/synth/test/mochitest.toml
  • dom/media/webspeech/synth/test/test_speech_cancel_on_navigation.html
diff --git a/dom/media/webspeech/synth/SpeechSynthesis.cpp b/dom/media/webspeech/synth/SpeechSynthesis.cpp
index 100fee9982e..0bb806013f8 100644
--- a/dom/media/webspeech/synth/SpeechSynthesis.cpp
+++ b/dom/media/webspeech/synth/SpeechSynthesis.cpp
@@ -270,6 +270,11 @@ void SpeechSynthesis::ForceEnd() {
   }
 }
 
+void SpeechSynthesis::DisconnectFromOwner() {
+  Cancel();
+  DOMEventTargetHelper::DisconnectFromOwner();
+}
+
 NS_IMETHODIMP
 SpeechSynthesis::Observe(nsISupports* aSubject, const char* aTopic,
                          const char16_t* aData) {
diff --git a/dom/media/webspeech/synth/SpeechSynthesis.h b/dom/media/webspeech/synth/SpeechSynthesis.h
index 7d69f98ba73..2c9e4ff062b 100644
--- a/dom/media/webspeech/synth/SpeechSynthesis.h
+++ b/dom/media/webspeech/synth/SpeechSynthesis.h
@@ -57,6 +57,8 @@ class SpeechSynthesis final : public DOMEventTargetHelper,
 
   void ForceEnd();
 
+  void DisconnectFromOwner() override;
+
   IMPL_EVENT_HANDLER(voiceschanged)
 
  private:
diff --git a/dom/media/webspeech/synth/test/file_speech_cancel_on_navigation_page1.html b/dom/media/webspeech/synth/test/file_speech_cancel_on_navigation_page1.html
new file mode 100644
index 00000000000..3714e5aff2c
--- /dev/null
+++ b/dom/media/webspeech/synth/test/file_speech_cancel_on_navigation_page1.html
@@ -0,0 +1,11 @@
+<html>
+<script>
+  var u = new SpeechSynthesisUtterance("hello");
+  u.lang = "it-IT-noend";
+  u.addEventListener("start", function() {
+    location = "file_speech_cancel_on_navigation_page2.html";
+  });
+  speechSynthesis.speak(u);
+</script>
+<body></body>
+</html>
diff --git a/dom/media/webspeech/synth/test/file_speech_cancel_on_navigation_page2.html b/dom/media/webspeech/synth/test/file_speech_cancel_on_navigation_page2.html
new file mode 100644
index 00000000000..5a4fa20a47e
--- /dev/null
+++ b/dom/media/webspeech/synth/test/file_speech_cancel_on_navigation_page2.html
@@ -0,0 +1,13 @@
+<html>
+<script>
+  window.ok = parent.ok;
+
+  var u = new SpeechSynthesisUtterance("hi");
+  u.addEventListener("end", function() {
+    ok(true, "Speech in new page completed: previous speech was cancelled on navigation.");
+    parent.onDone();
+  });
+  speechSynthesis.speak(u);
+</script>
+<body></body>
+</html>
diff --git a/dom/media/webspeech/synth/test/mochitest.toml b/dom/media/webspeech/synth/test/mochitest.toml
index 5180e2ea018..dc41cec561b 100644
--- a/dom/media/webspeech/synth/test/mochitest.toml
+++ b/dom/media/webspeech/synth/test/mochitest.toml
@@ -15,6 +15,8 @@ support-files = [
   "file_global_queue_cancel.html",
   "file_global_queue_pause.html",
   "file_speech_repeating_utterance.html",
+  "file_speech_cancel_on_navigation_page1.html",
+  "file_speech_cancel_on_navigation_page2.html",
 ]
 
 ["test_bfcache.html"]
@@ -38,3 +40,5 @@ support-files = [
 ["test_speech_repeating_utterance.html"]
 
 ["test_speech_simple.html"]
+
+["test_speech_cancel_on_navigation.html"]
diff --git a/dom/media/webspeech/synth/test/test_speech_cancel_on_navigation.html b/dom/media/webspeech/synth/test/test_speech_cancel_on_navigation.html
new file mode 100644
index 00000000000..72fd0b3fef0
--- /dev/null
+++ b/dom/media/webspeech/synth/test/test_speech_cancel_on_navigation.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test speech is cancelled when the page navigates away</title>
+  <script src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="common.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<iframe id="testFrame"></iframe>
+<pre id="test">
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+function onDone() {
+  SimpleTest.finish();
+}
+
+SpecialPowers.pushPrefEnv(
+  { set: [["media.webspeech.synth.enabled", true],
+          ["media.webspeech.synth.force_global_queue", true]] },
+  function() { loadSpeechTest("file_speech_cancel_on_navigation_page1.html"); }
+);
+
+</script>
+</pre>
+</body>
+</html>
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/dom/media/webspeech/synth/test/file_speech_cancel_on_navigation_page1.html b/dom/media/webspeech/synth/test/file_speech_cancel_on_navigation_page1.html
new file mode 100644
index 00000000000..3714e5aff2c
--- /dev/null
+++ b/dom/media/webspeech/synth/test/file_speech_cancel_on_navigation_page1.html
@@ -0,0 +1,11 @@
+<html>
+<script>
+  var u = new SpeechSynthesisUtterance("hello");
+  u.lang = "it-IT-noend";
+  u.addEventListener("start", function() {
+    location = "file_speech_cancel_on_navigation_page2.html";
+  });
+  speechSynthesis.speak(u);
+</script>
+<body></body>
+</html>
diff --git a/dom/media/webspeech/synth/test/file_speech_cancel_on_navigation_page2.html b/dom/media/webspeech/synth/test/file_speech_cancel_on_navigation_page2.html
new file mode 100644
index 00000000000..5a4fa20a47e
--- /dev/null
+++ b/dom/media/webspeech/synth/test/file_speech_cancel_on_navigation_page2.html
@@ -0,0 +1,13 @@
+<html>
+<script>
+  window.ok = parent.ok;
+
+  var u = new SpeechSynthesisUtterance("hi");
+  u.addEventListener("end", function() {
+    ok(true, "Speech in new page completed: previous speech was cancelled on navigation.");
+    parent.onDone();
+  });
+  speechSynthesis.speak(u);
+</script>
+<body></body>
+</html>
diff --git a/dom/media/webspeech/synth/test/mochitest.toml b/dom/media/webspeech/synth/test/mochitest.toml
index 5180e2ea018..dc41cec561b 100644
--- a/dom/media/webspeech/synth/test/mochitest.toml
+++ b/dom/media/webspeech/synth/test/mochitest.toml
@@ -15,6 +15,8 @@ support-files = [
   "file_global_queue_cancel.html",
   "file_global_queue_pause.html",
   "file_speech_repeating_utterance.html",
+  "file_speech_cancel_on_navigation_page1.html",
+  "file_speech_cancel_on_navigation_page2.html",
 ]
 
 ["test_bfcache.html"]
@@ -38,3 +40,5 @@ support-files = [
 ["test_speech_repeating_utterance.html"]
 
 ["test_speech_simple.html"]
+
+["test_speech_cancel_on_navigation.html"]
diff --git a/dom/media/webspeech/synth/test/test_speech_cancel_on_navigation.html b/dom/media/webspeech/synth/test/test_speech_cancel_on_navigation.html
new file mode 100644
index 00000000000..72fd0b3fef0
--- /dev/null
+++ b/dom/media/webspeech/synth/test/test_speech_cancel_on_navigation.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test speech is cancelled when the page navigates away</title>
+  <script src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="common.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<iframe id="testFrame"></iframe>
+<pre id="test">
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+function onDone() {
+  SimpleTest.finish();
+}
+
+SpecialPowers.pushPrefEnv(
+  { set: [["media.webspeech.synth.enabled", true],
+          ["media.webspeech.synth.force_global_queue", true]] },
+  function() { loadSpeechTest("file_speech_cancel_on_navigation_page1.html"); }
+);
+
+</script>
+</pre>
+</body>
+</html>
Loading diff…