{"id":"CVE-2026-75526","aliases":[],"url":"https://o3.security/vulnerability/CVE-2026-75526","summary":"django CMS: Stored XSS in edit-mode plugin exception rendering","details":"## Summary\n\nWhen plugin rendering fails in edit mode, django CMS renders a `cms-rendering-exception` block so editors can see that a placeholder could not be rendered. Older code built that block's heading by interpolating the exception message, placeholder/source strings, and the failing plugin's short description directly into an HTML string, then returned the placeholder output as safe markup.\n\nIf an editor could store HTML in data used by a plugin's `get_short_description()` (or in other values interpolated into the exception message), and that plugin later raised during edit-mode rendering, the payload was parsed as HTML in the staff user's browser. This is a stored XSS condition in the CMS editing context.\n\n## Impact\n\nThe vulnerable path is only reached when placeholder rendering catches a plugin rendering exception:\n\n```python\ntry:\n    placeholder_content = \"\".join(plugin_content)\nexcept Exception as e:\n    context[\"exc_info\"] = sys.exc_info()\n    placeholder_content = self.render_exception(\"rendering placeholder\", context, placeholder, editable)\n```\n\n`render_exception()` constructs a `message` from values that can include stored content:\n\n- `value` - the exception message.\n- `placeholder` - the placeholder string representation.\n- `placeholder.source` - the source object string representation, such as page content.\n- `instance.get_short_description()` - plugin-provided summary text, often derived from plugin model fields.\n\nIn the vulnerable implementation, that message was embedded directly into an HTML heading. The final placeholder content was later returned through `mark_safe`, so Django template autoescaping did not protect the heading.\n\n`settings.DEBUG` does not mitigate the issue: it only controls whether Django's traceback HTML is appended. The custom heading is rendered in edit mode regardless of `DEBUG`.\n\n## Patch\n\nEscape the custom exception heading before returning it as safe placeholder markup. The current fixed code uses `format_html`, which escapes `message` before inserting it into the heading:\n\n```python\nheading = format_html('<h2 class=\"cms-rendering-exception-title\">{}</h2>', message)\n```\n\nThe traceback HTML from `ExceptionReporter.get_traceback_html()` should remain separate from django CMS's custom heading; Django's traceback escaping does not protect additional HTML assembled by django CMS.\n\n## Workarounds\n\nUntil patched, reduce exposure by ensuring only fully trusted staff can edit plugins whose stored fields are included in `get_short_description()`, and fix or disable plugins that can be made to raise during edit-mode rendering. This is only a partial mitigation because the escaping bug is in the shared exception-rendering path.\n\n## References\n\n- `cms/plugin_rendering.py` - `ContentRenderer.render_placeholder`\n- `cms/plugin_rendering.py` - `ContentRenderer.render_exception`\n- Fixed code: `heading = format_html('<h2 class=\"cms-rendering-exception-title\">{}</h2>', message)`\n- Regression tests:\n  `cms.tests.test_plugin_renderers.TestExceptionCatchers.test_exception_in_plugin_render_escapes_user_content_in_edit_mode`,\n  `cms.tests.test_plugin_renderers.TestLegacyRendererExceptionCatcher.test_exception_in_plugin_render_escapes_user_content_in_edit_mode`","published":"2026-08-20T18:42:36Z","modified":"2026-08-20T19:00:07.468058366Z","cvss":{"score":4.4,"severity":"MEDIUM","vector":"CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:C/C:L/I:L/A:N"},"epss":null,"cisaKev":null,"exploitsKnown":null,"affectedPackages":[{"ecosystem":"PyPI","name":"django-cms","fixedVersion":"5.0.9"}],"fix":{"url":"https://github.com/django-cms/django-cms/pull/8711","label":"django-cms/django-cms#8711"},"references":[{"type":"WEB","url":"https://github.com/django-cms/django-cms/security/advisories/GHSA-hvq6-2r72-p2x7"},{"type":"WEB","url":"https://github.com/django-cms/django-cms/pull/8711"},{"type":"WEB","url":"https://github.com/django-cms/django-cms/commit/b56a568844ff3702495945f73a31d0868285bf88"},{"type":"PACKAGE","url":"https://github.com/django-cms/django-cms"},{"type":"WEB","url":"https://github.com/django-cms/django-cms/releases/tag/5.0.9"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-08-20T19:00:07.468058366Z"}}