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 <thestig@chromium.org>
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 <thestig@chromium.org>
Reviewed-by: Andy Phan <andyphan@chromium.org>
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