CVE-2026-93456 Overview
CVE-2026-93456 is a Cross-Site Request Forgery [CWE-352] vulnerability in django-page-cms through version 2.0.13. The maintainers exempted five admin mutation views in pages/admin/views.py from Django's built-in CSRF protection. Attackers can forge cross-origin requests that modify page content when a signed-in editor visits an attacker-controlled page. Because the mutation views accept unescaped content that later renders in the placeholder pipeline, forged requests can implant stored cross-site scripting (XSS) payloads that execute in every subsequent visitor's browser. The chained impact turns a single tricked editor into a persistent XSS foothold across the CMS.
Critical Impact
Authenticated editors can be coerced into storing attacker-controlled HTML and JavaScript that executes for all site visitors, enabling account takeover, defacement, and downstream malware delivery.
Affected Products
- django-page-cms versions through 2.0.13
- Django applications embedding the vulnerable admin views from pages/admin/views.py
- Web properties rendering placeholder content produced through pages/placeholders.py
Discovery Timeline
- 2026-09-18 - CVE-2026-93456 published to the National Vulnerability Database
- 2026-09-22 - Last updated in NVD database
Technical Details for CVE-2026-93456
Vulnerability Analysis
The defect is a missing anti-CSRF control on state-changing HTTP endpoints. Five admin mutation views in pages/admin/views.py (lines 51-53) are decorated in a way that removes Django's default CSRF middleware enforcement. These views accept POST requests that create or modify page content, including placeholder values consumed by pages/placeholders.py (lines 238-241).
Because placeholder content is later rendered without contextual escaping, the CSRF flaw compounds into a stored XSS delivery mechanism. An attacker hosts a page containing an auto-submitting form or fetch() call that targets a vulnerable admin endpoint. When a logged-in editor loads that page, the browser attaches session cookies and the mutation succeeds under the editor's identity. The injected markup then executes for every visitor that renders the affected page.
Root Cause
The root cause is the explicit removal of CSRF token validation on privileged mutation views combined with insufficient output encoding in the placeholder rendering path. Django's framework-level protection is bypassed by decorator choice, not by a browser flaw. See the GitHub Admin Views Code Snippet and the GitHub Placeholders Code Snippet for the affected lines.
Attack Vector
Exploitation requires an authenticated editor to visit an attacker-controlled URL while their CMS session is active. No credentials or elevated privileges are required on the attacker's side. User interaction is limited to loading a web page, which auto-triggers the forged request. Successful exploitation grants persistent script injection that affects all subsequent viewers of the modified page. Refer to the VulnCheck Advisory for CSRF and GitHub Issue #244 for additional context.
Detection Methods for CVE-2026-93456
Indicators of Compromise
- Unexpected page or placeholder edits recorded in Django admin audit logs outside normal editorial workflows.
- POST requests to the five mutation endpoints in pages/admin/views.py bearing a Referer or Origin header from an external domain.
- Rendered page content containing <script>, onerror=, onload=, or javascript: payloads not present in prior revisions.
- Editor sessions producing content mutations without a preceding GET of the corresponding admin form.
Detection Strategies
- Enable Django request logging on admin mutation endpoints and alert on cross-origin Referer/Origin values against the CMS host.
- Diff stored placeholder content against known-good revisions to surface injected HTML or script tags.
- Deploy a Content Security Policy (CSP) in report-only mode and monitor violation reports for inline script execution originating from rendered pages.
Monitoring Recommendations
- Centralize Django access and admin logs for correlation across sessions, source IPs, and user agents.
- Alert on any HTTP 200 response to the affected mutation views where the request lacks a valid same-origin Referer.
- Track editor account behavior for anomalous edit velocity or off-hours mutations that may indicate CSRF-driven activity.
How to Mitigate CVE-2026-93456
Immediate Actions Required
- Restore CSRF protection on the five affected views in pages/admin/views.py by removing any @csrf_exempt decorators and relying on Django's default middleware.
- Restrict access to /admin/ paths behind VPN, IP allowlists, or SSO to reduce cross-origin exposure while a fix is validated.
- Audit stored page and placeholder content for injected <script> tags and event handlers, then revert compromised revisions.
- Rotate session keys and force re-authentication for all editor accounts to invalidate any hijacked sessions.
Patch Information
At the time of publication, no fixed release of django-page-cms beyond 2.0.13 has been referenced in the NVD entry. Track the GitHub Repository for Django Page CMS and GitHub Issue #244 for remediation status. Organizations should apply a private patch that re-enables CSRF enforcement on the affected views and adds contextual output escaping in the placeholder rendering path.
Workarounds
- Apply a local monkey-patch or fork that removes @csrf_exempt from the five mutation views and validates the CSRF token on every POST.
- Enforce a strict Content Security Policy that disallows inline scripts to blunt stored XSS execution even if CSRF succeeds.
- Configure SameSite=Strict on session cookies so cross-site requests do not carry editor credentials.
- Require step-up authentication or CAPTCHA on admin mutation flows to break automated CSRF chains.
# Example Django settings hardening to reduce CSRF exposure
SESSION_COOKIE_SAMESITE = "Strict"
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
CSRF_COOKIE_HTTPONLY = True
SECURE_REFERRER_POLICY = "same-origin"
# Enforce CSP to limit stored XSS blast radius
CSP_DEFAULT_SRC = ("'self'",)
CSP_SCRIPT_SRC = ("'self'",)
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.