diff --git a/CHANGES/+cve-2026-84232.bugfix b/CHANGES/+cve-2026-84232.bugfix new file mode 100644 index 00000000000..dc1fb1b50ca --- /dev/null +++ b/CHANGES/+cve-2026-84232.bugfix @@ -0,0 +1,2 @@ +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/pulpcore/content/handler.py b/pulpcore/content/handler.py index 2628a948f76..2301d57ed9f 100644 --- a/pulpcore/content/handler.py +++ b/pulpcore/content/handler.py @@ -764,6 +764,7 @@ async def _match_and_stream(self, path, request): ) ca = ContentArtifact(relative_path=original_rel_path) ra = RemoteArtifact(remote=remote, url=url, content_artifact=ca) + self._set_secure_headers(os.path.basename(ca.relative_path), headers) try: return await self._stream_remote_artifact( request, @@ -941,6 +942,12 @@ def _save_artifact(self, download_result, remote_artifact, request=None): content_artifact.save() return artifact + def _set_secure_headers(self, filename, headers): + 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" + async def _serve_content_artifact(self, content_artifact, headers, request): """ Handle response for a Content Artifact with the file present. @@ -978,6 +985,7 @@ def _set_params_from_headers(hdrs, storage_domain): domain = get_domain() storage = domain.get_storage() + self._set_secure_headers(os.path.basename(content_artifact.relative_path), headers) if domain.storage_class == "pulpcore.app.models.storage.FileSystem": path = storage.path(artifact_name) if not os.path.exists(path): @@ -1049,6 +1057,9 @@ async def _stream_remote_artifact(self, request, response, remote_artifact, save size = remote_artifact.size or "*" raise HTTPRequestRangeNotSatisfiable(headers={"Content-Range": f"bytes */{size}"}) + self._set_secure_headers( + os.path.basename(remote_artifact.content_artifact.relative_path), response.headers + ) actual_content_length = None if range_start or range_stop: