Chrome · PDF › PDF
CVE-2026-113251
UAF in PDF (PDF)
Overview
Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifchrome/browser/plugins/plugin_response_interceptor_url_loader_throttle.cc |
modified | |
IN_PROC_BROWSER_TEST_Pchrome/browser/pdf/pdf_extension_test.cc |
modified |
Files Changed
chrome/browser/pdf/pdf_extension_test.ccchrome/browser/plugins/plugin_response_interceptor_url_loader_throttle.cc
Patch
From 0520a5aa3f76496749fca4c1f55d9cedb12f6517 Mon Sep 17 00:00:00 2001 From: Lei Zhang <[email protected]> Date: Wed, 16 Sep 2026 17:02:31 -0700 Subject: [PATCH] [PDF] Do not load PDF Viewer for HTTP(S) text/plain responses When a web server serves a PDF containing binary bytes in the first 1024 bytes with a "text/plain" Content-Type header, net::SniffMimeType() sniffs the response MIME type as "application/pdf". Before this CL, PluginResponseInterceptorURLLoaderThrottle intercepted the navigation and launched the PDF Viewer, only for the PDF Viewer to reject the "text/plain" Content-Type header and show a load error. Fix this by checking the original HTTP(S) Content-Type header in PluginResponseInterceptorURLLoaderThrottle::WillProcessResponse() when `response_head->mime_type` is "application/pdf". If the original header MIME type is "text/plain", revert `response_head->mime_type` back to it so the PDF Viewer does not launch and the content renders inline as plain text. Update PDFExtensionTest.BinaryPdfServedAsTextPlain to reflect this new behavior. TAG=agy CONV=ee25eb48-0a12-4307-a005-1b2de4305209 Bug: 40056239 Change-Id: Iee8490e34ca9bb19b273ccb3539e2b34ba7c7b16 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8419586 Commit-Queue: Lei Zhang <[email protected]> Reviewed-by: Andy Phan <[email protected]> Cr-Commit-Position: refs/heads/main@{#1699353} --- diff --git a/chrome/browser/plugins/plugin_response_interceptor_url_loader_throttle.cc b/chrome/browser/plugins/plugin_response_interceptor_url_loader_throttle.cc index 529410b..6e8f30c 100644 --- a/chrome/browser/plugins/plugin_response_interceptor_url_loader_throttle.cc +++ b/chrome/browser/plugins/plugin_response_interceptor_url_loader_throttle.cc @@ -155,16 +155,27 @@ } #if BUILDFLAG(ENABLE_PDF) - // text/pdf is an alias for application/pdf for the purpose of invoking the - // built-in PDF viewer (crbug.com/40774340). Canonicalize it here -- before - // the download decision below -- so the download pref, the PDF viewer - // machinery, and the committed WebContents contents MIME type uniformly - // observe application/pdf, preserving the invariant that a full-page PDF's - // contents MIME type is application/pdf. if (response_head->mime_type == "text/pdf") { + // text/pdf is an alias for application/pdf for the purpose of invoking the + // built-in PDF viewer (crbug.com/40774340). Canonicalize it here -- before + // the download decision below -- so the download pref, the PDF viewer + // machinery, and the committed WebContents contents MIME type uniformly + // observe application/pdf, preserving the invariant that a full-page PDF's + // contents MIME type is application/pdf. response_head->mime_type = pdf::kPDFMimeType; + } else if (response_head->mime_type == pdf::kPDFMimeType && + response_url.SchemeIsHTTPOrHTTPS() && response_head->headers) { + // If net::SniffMimeType() sniffed an HTTP(S) "text/plain" response as + // "application/pdf", revert `response_head->mime_type` back to + // "text/plain". The PDF viewer rejects HTTP(S) responses with a + // "text/plain" Content-Type header, so do not intercept the response. + std::string original_header_mime_type; + if (response_head->headers->GetMimeType(&original_header_mime_type) && + original_header_mime_type == "text/plain") { + response_head->mime_type = original_header_mime_type; + } } -#endif +#endif // BUILDFLAG(ENABLE_PDF) if (content::download_utils::MustDownload( web_contents->GetBrowserContext(), response_url, diff --git a/chrome/browser/pdf/pdf_extension_test.cc b/chrome/browser/pdf/pdf_extension_test.cc index f3780bc..c99b6f0b 100644 --- a/chrome/browser/pdf/pdf_extension_test.cc +++ b/chrome/browser/pdf/pdf_extension_test.cc @@ -1052,17 +1052,14 @@ } IN_PROC_BROWSER_TEST_P(PDFExtensionTest, BinaryPdfServedAsTextPlain) { - // When a PDF contains binary bytes in the first 1024 bytes, - // net::SniffMimeType() sniffs "text/plain" for binary content and matches the - // "%PDF-" magic number, overriding the MIME type to "application/pdf" and - // loading the PDF Viewer. However, DocumentLoaderImpl::Init() rejects HTTP - // responses with a "text/plain" Content-Type header, so loading the PDF - // document fails. - // TODO(crbug.com/40056239): Render as plain text instead? + // Even when a PDF contains binary bytes in the first 1024 bytes, causing + // net::SniffMimeType() to match the "%PDF-" magic number, the PDF Viewer does + // not load for HTTP responses with a "text/plain" Content-Type header and the + // content is rendered as plain text. const GURL url = embedded_test_server()->GetURL("/text_plain/pdf/test.pdf"); - EXPECT_FALSE(LoadPdf(url)); - EXPECT_EQ(pdf::kPDFMimeType, GetActiveWebContents()->GetContentsMimeType()); - EXPECT_EQ(1, CountPDFProcesses()); + ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url)); + EXPECT_EQ("text/plain", GetActiveWebContents()->GetContentsMimeType()); + EXPECT_EQ(0, CountPDFProcesses()); } IN_PROC_BROWSER_TEST_P(PDFExtensionTest, MostlyTextPdfServedAsTextPlain) {
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/chrome/browser/pdf/pdf_extension_test.cc b/chrome/browser/pdf/pdf_extension_test.cc
index f3780bc..c99b6f0b 100644
--- a/chrome/browser/pdf/pdf_extension_test.cc
+++ b/chrome/browser/pdf/pdf_extension_test.cc
@@ -1052,17 +1052,14 @@
}
IN_PROC_BROWSER_TEST_P(PDFExtensionTest, BinaryPdfServedAsTextPlain) {
- // When a PDF contains binary bytes in the first 1024 bytes,
- // net::SniffMimeType() sniffs "text/plain" for binary content and matches the
- // "%PDF-" magic number, overriding the MIME type to "application/pdf" and
- // loading the PDF Viewer. However, DocumentLoaderImpl::Init() rejects HTTP
- // responses with a "text/plain" Content-Type header, so loading the PDF
- // document fails.
- // TODO(crbug.com/40056239): Render as plain text instead?
+ // Even when a PDF contains binary bytes in the first 1024 bytes, causing
+ // net::SniffMimeType() to match the "%PDF-" magic number, the PDF Viewer does
+ // not load for HTTP responses with a "text/plain" Content-Type header and the
+ // content is rendered as plain text.
const GURL url = embedded_test_server()->GetURL("/text_plain/pdf/test.pdf");
- EXPECT_FALSE(LoadPdf(url));
- EXPECT_EQ(pdf::kPDFMimeType, GetActiveWebContents()->GetContentsMimeType());
- EXPECT_EQ(1, CountPDFProcesses());
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
+ EXPECT_EQ("text/plain", GetActiveWebContents()->GetContentsMimeType());
+ EXPECT_EQ(0, CountPDFProcesses());
}
IN_PROC_BROWSER_TEST_P(PDFExtensionTest, MostlyTextPdfServedAsTextPlain) {
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