Firefox · DOM
CVE-2026-16407
Logic Error in DOM
Overview
Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
fortesting/web-platform/tests/service-workers/service-worker/resources/registration-tests-mime-types.js |
modified | |
promise_testtesting/web-platform/tests/service-workers/service-worker/resources/registration-tests-mime-types.js |
modified |
Files Changed
dom/serviceworkers/ServiceWorkerScriptCache.cppdom/workers/loader/NetworkLoadHandler.cpptesting/web-platform/tests/service-workers/service-worker/resources/import-scripts-mime-types-worker.jstesting/web-platform/tests/service-workers/service-worker/resources/registration-tests-mime-types.js
Patch
diff --git a/dom/serviceworkers/ServiceWorkerScriptCache.cpp b/dom/serviceworkers/ServiceWorkerScriptCache.cpp
index 6a1211f96de..2e80b226620 100644
--- a/dom/serviceworkers/ServiceWorkerScriptCache.cpp
+++ b/dom/serviceworkers/ServiceWorkerScriptCache.cpp
@@ -1087,9 +1087,12 @@ CompareNetwork::OnStreamComplete(nsIStreamLoader* aLoader,
}
auto mimeTypeUTF16 = NS_ConvertUTF8toUTF16(mimeType);
+ // The top-level service worker script must be served with a JavaScript
+ // MIME type. JSON is only permitted for non-top-level (imported) modules,
+ // such as `import data from "./x.json" with { type: "json" }`.
if (mimeTypeUTF16.IsEmpty() ||
!(nsContentUtils::IsJavascriptMIMEType(mimeTypeUTF16) ||
- nsContentUtils::IsJsonMimeType(mimeTypeUTF16))) {
+ (!mIsMainScript && nsContentUtils::IsJsonMimeType(mimeTypeUTF16)))) {
ServiceWorkerManager::LocalizeAndReportToAllClients(
mRegistration->Scope(), "ServiceWorkerRegisterMimeTypeError2",
nsTArray<nsString>{NS_ConvertUTF8toUTF16(mRegistration->Scope()),
diff --git a/dom/workers/loader/NetworkLoadHandler.cpp b/dom/workers/loader/NetworkLoadHandler.cpp
index 75a46add9dd..7d384eb01d9 100644
--- a/dom/workers/loader/NetworkLoadHandler.cpp
+++ b/dom/workers/loader/NetworkLoadHandler.cpp
@@ -353,8 +353,12 @@ nsresult NetworkLoadHandler::PrepareForRequest(nsIRequest* aRequest) {
auto mimeTypeUTF16 = NS_ConvertUTF8toUTF16(mimeType);
if (!nsContentUtils::IsJavascriptMIMEType(mimeTypeUTF16)) {
- // JSON is allowed as a non-toplevel.
+ // JSON is only allowed for non-toplevel JSON module imports, not for
+ // classic importScripts() or the top-level worker script.
if (!((!loadContext->IsTopLevel() &&
+ loadContext->mRequest->IsModuleRequest() &&
+ loadContext->mRequest->AsModuleRequest()->mModuleType ==
+ JS::ModuleType::JSON &&
nsContentUtils::IsJsonMimeType(mimeTypeUTF16))
#ifdef NIGHTLY_BUILD
// Allow wasm modules.
diff --git a/testing/web-platform/tests/service-workers/service-worker/resources/import-scripts-mime-types-worker.js b/testing/web-platform/tests/service-workers/service-worker/resources/import-scripts-mime-types-worker.js
index d4f1f3e26d8..7658eeace69 100644
--- a/testing/web-platform/tests/service-workers/service-worker/resources/import-scripts-mime-types-worker.js
+++ b/testing/web-platform/tests/service-workers/service-worker/resources/import-scripts-mime-types-worker.js
@@ -1,6 +1,11 @@
const badMimeTypes = [
null, // no MIME type
'text/plain',
+ // JSON is only valid for JSON module imports, never for classic
+ // importScripts(), even when the body is valid JavaScript.
+ 'application/json',
+ 'text/json',
+ 'application/manifest+json',
];
const validMimeTypes = [
diff --git a/testing/web-platform/tests/service-workers/service-worker/resources/registration-tests-mime-types.js b/testing/web-platform/tests/service-workers/service-worker/resources/registration-tests-mime-types.js
index 037e6c0fde2..7a64cd91e41 100644
--- a/testing/web-platform/tests/service-workers/service-worker/resources/registration-tests-mime-types.js
+++ b/testing/web-platform/tests/service-workers/service-worker/resources/registration-tests-mime-types.js
@@ -21,6 +21,32 @@ function registration_tests_mime_types(register_method) {
'Registration of plain text script should fail.');
}, 'Registering script with bad MIME type');
+ // The top-level service worker script must have a JavaScript MIME type. A
+ // JSON MIME type is only valid for imported (non-top-level) modules, so
+ // registering a top-level script served as JSON must fail even when the body
+ // happens to be valid JavaScript.
+ const jsonMimeTypes = [
+ 'application/json',
+ 'text/json',
+ 'application/manifest+json',
+ ];
+
+ for (const jsonMimeType of jsonMimeTypes) {
+ promise_test(function(t) {
+ // Encode the MIME type so characters such as '+' survive the query
+ // string instead of being decoded to a space by the server.
+ var script =
+ `resources/mime-type-worker.py?mime=${encodeURIComponent(jsonMimeType)}`;
+ // Use a scope unique to each MIME type so the registrations don't
+ // interfere with one another.
+ var scope = `resources/scope/json-mime-type-worker/${jsonMimeType}`;
+ return promise_rejects_dom(t,
+ 'SecurityError',
+ register_method(script, {scope: scope}),
+ 'Registration of JSON MIME type script should fail.');
+ }, `Registering script with JSON MIME type ${jsonMimeType}`);
+ }
+
/**
* ServiceWorkerContainer.register() should throw a TypeError, according to
* step 17.1 of https://w3c.github.io/ServiceWorker/#importscripts
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/testing/web-platform/tests/service-workers/service-worker/resources/import-scripts-mime-types-worker.js b/testing/web-platform/tests/service-workers/service-worker/resources/import-scripts-mime-types-worker.js
index d4f1f3e26d8..7658eeace69 100644
--- a/testing/web-platform/tests/service-workers/service-worker/resources/import-scripts-mime-types-worker.js
+++ b/testing/web-platform/tests/service-workers/service-worker/resources/import-scripts-mime-types-worker.js
@@ -1,6 +1,11 @@
const badMimeTypes = [
null, // no MIME type
'text/plain',
+ // JSON is only valid for JSON module imports, never for classic
+ // importScripts(), even when the body is valid JavaScript.
+ 'application/json',
+ 'text/json',
+ 'application/manifest+json',
];
const validMimeTypes = [
diff --git a/testing/web-platform/tests/service-workers/service-worker/resources/registration-tests-mime-types.js b/testing/web-platform/tests/service-workers/service-worker/resources/registration-tests-mime-types.js
index 037e6c0fde2..7a64cd91e41 100644
--- a/testing/web-platform/tests/service-workers/service-worker/resources/registration-tests-mime-types.js
+++ b/testing/web-platform/tests/service-workers/service-worker/resources/registration-tests-mime-types.js
@@ -21,6 +21,32 @@ function registration_tests_mime_types(register_method) {
'Registration of plain text script should fail.');
}, 'Registering script with bad MIME type');
+ // The top-level service worker script must have a JavaScript MIME type. A
+ // JSON MIME type is only valid for imported (non-top-level) modules, so
+ // registering a top-level script served as JSON must fail even when the body
+ // happens to be valid JavaScript.
+ const jsonMimeTypes = [
+ 'application/json',
+ 'text/json',
+ 'application/manifest+json',
+ ];
+
+ for (const jsonMimeType of jsonMimeTypes) {
+ promise_test(function(t) {
+ // Encode the MIME type so characters such as '+' survive the query
+ // string instead of being decoded to a space by the server.
+ var script =
+ `resources/mime-type-worker.py?mime=${encodeURIComponent(jsonMimeType)}`;
+ // Use a scope unique to each MIME type so the registrations don't
+ // interfere with one another.
+ var scope = `resources/scope/json-mime-type-worker/${jsonMimeType}`;
+ return promise_rejects_dom(t,
+ 'SecurityError',
+ register_method(script, {scope: scope}),
+ 'Registration of JSON MIME type script should fail.');
+ }, `Registering script with JSON MIME type ${jsonMimeType}`);
+ }
+
/**
* ServiceWorkerContainer.register() should throw a TypeError, according to
* step 17.1 of https://w3c.github.io/ServiceWorker/#importscripts
Loading diff…
References
On This Page