diff --git a/CHANGES/+cve-2026-84232.bugfix b/CHANGES/+cve-2026-84232.bugfix new file mode 100644 index 00000000000..81760492f36 --- /dev/null +++ b/CHANGES/+cve-2026-84232.bugfix @@ -0,0 +1,4 @@ +Insures that `Content-Disposition`, `Content-Security-Policy`, and `X-Content-Type-Options` +are set consistently in the content-app. + +This addresses CVE-2026-84232. diff --git a/pulp_file/tests/functional/api/test_mime_types.py b/pulp_file/tests/functional/api/test_mime_types.py index e39d94713fa..d04aad827d5 100644 --- a/pulp_file/tests/functional/api/test_mime_types.py +++ b/pulp_file/tests/functional/api/test_mime_types.py @@ -61,7 +61,17 @@ async def fetch_mimetypes(): async def get_content_type(extension, content_unit): url = urljoin(distribution_base_url, content_unit.relative_path) async with session.get(url) as response: - return extension, response.headers.get("Content-Type") + hdrs = response.headers + assert hdrs.get("Content-Disposition") and hdrs.get( + "Content-Disposition" + ).startswith("attachment;filename=") + assert hdrs.get("Content-Security-Policy") and "sandbox" in hdrs.get( + "Content-Security-Policy" + ) + assert hdrs.get("X-Content-Type-Options") and "nosniff" in hdrs.get( + "X-Content-Type-Options" + ) + return extension, hdrs.get("Content-Type") pairs = await asyncio.gather( *(get_content_type(ext, unit) for ext, unit in files.items()) diff --git a/pulpcore/content/handler.py b/pulpcore/content/handler.py index dcaef910600..83da17b0dfa 100644 --- a/pulpcore/content/handler.py +++ b/pulpcore/content/handler.py @@ -1103,10 +1103,6 @@ def _set_params_from_headers(hdrs, storage_domain): return params def _build_url(**kwargs): - filename = os.path.basename(content_artifact.relative_path) - content_disposition = f"attachment;filename={filename}" - - headers["Content-Disposition"] = content_disposition parameters = _set_params_from_headers(headers, domain.storage_class) storage_url = storage.url(artifact_name, parameters=parameters, **kwargs) @@ -1118,6 +1114,12 @@ def _build_url(**kwargs): storage = domain.get_storage() headers["X-PULP-ARTIFACT-SIZE"] = str(artifact_file.size) + filename = os.path.basename(content_artifact.relative_path) + content_disposition = f"attachment;filename={filename}" + headers["Content-Disposition"] = content_disposition + headers["Content-Security-Policy"] = "default-src 'none'; sandbox" + headers["X-Content-Type-Options"] = "nosniff" + if domain.storage_class == "pulpcore.app.models.storage.FileSystem": path = storage.path(artifact_name) if not os.path.exists(path):