Chrome · MHTML
CVE-2026-17954
Logic Error in MHTML
Overview
Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
NavigationMhtmlImprovementsBrowserTestcontent/browser/navigation_mhtml_browsertest.cc |
modified | |
NavigationMhtmlImprovementsBrowserTestcontent/browser/navigation_mhtml_browsertest.cc |
modified |
Files Changed
content/browser/navigation_mhtml_browsertest.cccontent/browser/renderer_host/render_frame_host_impl.cc
Patch
From 7071428f8304742aea0b30bf583583cceb104476 Mon Sep 17 00:00:00 2001 From: Patrick Meenan <[email protected]> Date: Wed, 03 Jun 2026 06:33:08 -0700 Subject: [PATCH] Block WebSocket and WebTransport connections in MHTML documents MHTML documents are intended to be strictly sandboxed and isolated from the network. However, WebSockets and WebTransport both connect directly to the browser process via Mojo, bypassing the renderer-side resource fetcher network isolation. This CL adds browser-side verification to CreateWebSocketConnector and CreateWebTransportConnector in RenderFrameHostImpl. Requests originating from MHTML documents now correctly trigger a bad Mojo message and terminate the requesting renderer process. Added regression integration tests to verify WebSocket and WebTransport bindings are successfully blocked and terminated. Bug: 517383492 Change-Id: I1a9ca360f381566f6445baeba6e9a8c8eda2eab4 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7891435 Reviewed-by: Arthur Sonzogni <[email protected]> Commit-Queue: Patrick Meenan <[email protected]> Cr-Commit-Position: refs/heads/main@{#1640884} --- diff --git a/content/browser/navigation_mhtml_browsertest.cc b/content/browser/navigation_mhtml_browsertest.cc index 682db42..df1989b 100644 --- a/content/browser/navigation_mhtml_browsertest.cc +++ b/content/browser/navigation_mhtml_browsertest.cc @@ -965,4 +965,61 @@ EXPECT_EQ(1, num_documents); } +// Helper test fixture to enable `kMHTML_Improvements`. Enabling this feature +// allows script execution in MHTML documents, which is necessary for the tests +// to execute the JavaScript payload that triggers the Mojo IPC request. +class NavigationMhtmlImprovementsBrowserTest + : public NavigationMhtmlBrowserTest { + public: + NavigationMhtmlImprovementsBrowserTest() { + scoped_feature_list_.InitAndEnableFeature( + blink::features::kMHTML_Improvements); + } + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +IN_PROC_BROWSER_TEST_F(NavigationMhtmlImprovementsBrowserTest, + MhtmlBlocksWebSocket) { + MhtmlArchive mhtml_archive; + mhtml_archive.AddHtmlDocument(GURL("http://example.com"), "MHTML content"); + GURL mhtml_url = mhtml_archive.Write("index.mhtml"); + EXPECT_TRUE(NavigateToURL(shell(), mhtml_url)); + + RenderFrameHostImpl* main_document = main_frame_host(); + EXPECT_TRUE(main_document->is_mhtml_document()); + + RenderProcessHostBadMojoMessageWaiter kill_waiter( + main_document->GetProcess()); + + ExecuteScriptAsync(main_document, "new WebSocket('ws://127.0.0.1');"); + + EXPECT_EQ( + "Received bad user message: WebSockets are not allowed in MHTML " + "documents.", + kill_waiter.Wait()); +} + +IN_PROC_BROWSER_TEST_F(NavigationMhtmlImprovementsBrowserTest, + MhtmlBlocksWebTransport) { + MhtmlArchive mhtml_archive; + mhtml_archive.AddHtmlDocument(GURL("http://example.com"), "MHTML content"); + GURL mhtml_url = mhtml_archive.Write("index.mhtml"); + EXPECT_TRUE(NavigateToURL(shell(), mhtml_url)); + + RenderFrameHostImpl* main_document = main_frame_host(); + EXPECT_TRUE(main_document->is_mhtml_document()); + + RenderProcessHostBadMojoMessageWaiter kill_waiter( + main_document->GetProcess()); + + ExecuteScriptAsync(main_document, "new WebTransport('https://127.0.0.1');"); + + EXPECT_EQ( + "Received bad user message: WebTransport is not allowed in MHTML " + "documents.", + kill_waiter.Wait()); +} + } // namespace content diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc index 7d052f9..e08049d0 100644 --- a/content/browser/renderer_host/render_frame_host_impl.cc +++ b/content/browser/renderer_host/render_frame_host_impl.cc @@ -14758,6 +14758,10 @@ void RenderFrameHostImpl::CreateWebSocketConnector( mojo::PendingReceiver<blink::mojom::WebSocketConnector> receiver) { + if (is_mhtml_document()) { + mojo::ReportBadMessage("WebSockets are not allowed in MHTML documents."); + return; + } mojo::MakeSelfOwnedReceiver( std::make_unique<WebSocketConnectorImpl>( GlobalRenderFrameHostId(GetProcess()->GetID(), routing_id_), @@ -14768,6 +14772,10 @@ void RenderFrameHostImpl::CreateWebTransportConnector( mojo::PendingReceiver<blink::mojom::WebTransportConnector> receiver) { + if (is_mhtml_document()) { + mojo::ReportBadMessage("WebTransport is not allowed in MHTML documents."); + return; + } mojo::MakeSelfOwnedReceiver( std::make_unique<WebTransportConnectorImpl>( GetProcess()->GetDeprecatedID(), weak_ptr_factory_.GetWeakPtr(),
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/content/browser/navigation_mhtml_browsertest.cc b/content/browser/navigation_mhtml_browsertest.cc
index 682db42..df1989b 100644
--- a/content/browser/navigation_mhtml_browsertest.cc
+++ b/content/browser/navigation_mhtml_browsertest.cc
@@ -965,4 +965,61 @@
EXPECT_EQ(1, num_documents);
}
+// Helper test fixture to enable `kMHTML_Improvements`. Enabling this feature
+// allows script execution in MHTML documents, which is necessary for the tests
+// to execute the JavaScript payload that triggers the Mojo IPC request.
+class NavigationMhtmlImprovementsBrowserTest
+ : public NavigationMhtmlBrowserTest {
+ public:
+ NavigationMhtmlImprovementsBrowserTest() {
+ scoped_feature_list_.InitAndEnableFeature(
+ blink::features::kMHTML_Improvements);
+ }
+
+ private:
+ base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_F(NavigationMhtmlImprovementsBrowserTest,
+ MhtmlBlocksWebSocket) {
+ MhtmlArchive mhtml_archive;
+ mhtml_archive.AddHtmlDocument(GURL("http://example.com"), "MHTML content");
+ GURL mhtml_url = mhtml_archive.Write("index.mhtml");
+ EXPECT_TRUE(NavigateToURL(shell(), mhtml_url));
+
+ RenderFrameHostImpl* main_document = main_frame_host();
+ EXPECT_TRUE(main_document->is_mhtml_document());
+
+ RenderProcessHostBadMojoMessageWaiter kill_waiter(
+ main_document->GetProcess());
+
+ ExecuteScriptAsync(main_document, "new WebSocket('ws://127.0.0.1');");
+
+ EXPECT_EQ(
+ "Received bad user message: WebSockets are not allowed in MHTML "
+ "documents.",
+ kill_waiter.Wait());
+}
+
+IN_PROC_BROWSER_TEST_F(NavigationMhtmlImprovementsBrowserTest,
+ MhtmlBlocksWebTransport) {
+ MhtmlArchive mhtml_archive;
+ mhtml_archive.AddHtmlDocument(GURL("http://example.com"), "MHTML content");
+ GURL mhtml_url = mhtml_archive.Write("index.mhtml");
+ EXPECT_TRUE(NavigateToURL(shell(), mhtml_url));
+
+ RenderFrameHostImpl* main_document = main_frame_host();
+ EXPECT_TRUE(main_document->is_mhtml_document());
+
+ RenderProcessHostBadMojoMessageWaiter kill_waiter(
+ main_document->GetProcess());
+
+ ExecuteScriptAsync(main_document, "new WebTransport('https://127.0.0.1');");
+
+ EXPECT_EQ(
+ "Received bad user message: WebTransport is not allowed in MHTML "
+ "documents.",
+ kill_waiter.Wait());
+}
+
} // namespace content
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