5.1.2 release notes¶
August 27, 2026
Welcome to django CMS 5.1.2!
These release notes cover what has changed since django CMS 5.1.1. This is a patch release. It contains no new migrations, but it fixes the 5.1.1 migrations so that they also apply on SQLite, and it tightens authorization on several endpoints. Projects that could not apply the 5.1.1 migrations should upgrade directly to 5.1.2.
If you are upgrading from django CMS 5.0.x or earlier, read the 5.1.0 release notes first — they cover the backward incompatible changes, deprecations, and removals of the 5.1 series.
Django and Python compatibility¶
django CMS 5.1 supports Django 5.2, 6.0, and 6.1. Django 4.2, 5.0, and 5.1 are no longer supported because those series no longer receive upstream maintenance. We highly recommend and only support the latest release of each supported series.
It supports Python 3.10, 3.11, 3.12, 3.13, and 3.14.
Release highlights¶
Authorization fixes. The edit and view endpoints did not check placeholder permissions, so a user without change permission on a placeholder could still reach its editing endpoints. Setting a new home page no longer only requires permission on the new page, but also on the page that is being demoted.
The 5.1.1 migrations now apply on SQLite.
cms.0044failed on SQLite when djangocms-versioning was installed, which blocked the upgrade to 5.1.1 for those projects. The migration itself is unchanged in what it produces, so no new migration is added and databases already migrated on 5.1.1 are unaffected.Manually entered page slugs are kept. Changing a page title overwrote a slug that had been entered by hand — a regression from moving the slug onto
PageContentin 5.1.1.Content Security Policy nonces on Django 6.1. The admin, toolbar and wizard templates emit the nonce Django 6.1 provides, so django CMS works under a nonce-based CSP without
unsafe-inline.
How to upgrade to 5.1.2¶
This release adds no migrations and no backward incompatible changes. Upgrade django CMS:
python -m pip install --upgrade "django-cms==5.1.2"
Then collect static files and run the django CMS checks:
python manage.py collectstatic --noinput
python manage.py cms check
Collecting static files is required: this release changes the toolbar
JavaScript and the path from which the welcome page loads welcome.js.
Projects upgrading from 5.1.0 also have to apply the migrations introduced in 5.1.1:
python manage.py migrate
Those are the two migrations described in the
5.1.1 release notes. 5.1.2 only repairs
cms.0044_pagecontent_slug_overwrite_url so that it also runs on SQLite when
djangocms-versioning is installed; the resulting schema and data are unchanged,
so databases that migrated successfully on 5.1.1 need no further action.
What’s new in 5.1.2¶
Security fixes¶
Editing endpoints did not check placeholder permissions¶
render_object_endpoint() resolved the requested object and rendered it
without an object-level view check, unlike the structure endpoint and, for
pages, render_page(). Any staff user could therefore read the rendered
plugin content of any frontend-editable object, including placeholders they
have no access to. The endpoint now calls
user_can_view_placeholder_source() and raises Http404 when the check
fails. Mutations were, and remain, gated by change permission at the plugin
endpoints.
Setting a home page did not require permission on the previous one¶
PageAdmin.set_home() only checked change permission on the page being
promoted. Promoting a page demotes the current home page and rewrites the URL
paths of both trees, so a user with change permission on a single page could
change the URLs of a page tree they have no permission for. Change permission
on the current home page is now required as well.
Editable content could inject markup into the toolbar¶
When refreshing the toolbar, Toolbar._refreshMarkup() copied the children
of every element matching .cms-toolbar on the page. Editable content that
renders an element with that class — plugin content, for instance — had its
markup copied into the live toolbar. Only the first match is used now.
CSRF form for POST toolbar items was assembled from a string¶
Toolbar._sendPostRequest() built its hidden form by concatenating the item’s
href and the CSRF token into an HTML string, so a quote or angle bracket in
either could break out of the attribute it was placed in. The form and its token
input are now created through DOM APIs, which puts both values in attribute
positions that cannot be escaped.
Release pipeline¶
The PyPI publishing workflows were split into a build job and a publish job, so
that the job running third-party code — pip, the build backend,
check-wheel-contents — no longer holds the id-token: write permission
needed to mint an OIDC token for trusted publishing. The build tooling is
hash-pinned in .github/requirements/build.txt and installed with
--require-hashes, the distribution is built with --no-isolation so the
backend comes from those pins, and pypa/gh-action-pypi-publish is pinned to
a commit instead of the mutable release/v1 branch.
Features¶
Support Content Security Policy nonces introduced in Django 6.1 (#8792) – Fabian Braun
Bug Fixes¶
Enforce placeholder permissions on the edit and view endpoints (#8794) – Fabian Braun
Fix
GrouperModelAdminignoring the read-only context for content objects without a language field (#8799) – Fabian BraunPrevent a manually entered page slug from being overwritten when changing the page title (#8796) – Fabian Braun
Avoid needlessly clearing the permission caches on Django 6.1 signals (#8791) – Fabian Braun
Allow copying plugins from write-protected (published) content (#8786) – Fabian Braun
Harden the toolbar JavaScript (#8790) – Fabian Braun
Require permission to change the previous home page before setting a new one (#8789) – Fabian Braun
Explicitly escape the CSRF token used for POST requests (#8787) – Fabian Braun
Harden the PyPI publish workflows (#8788) – Fabian Braun
Fix copying a page dropping its login-required property (#8785) – Fabian Braun
Limit the number of plugins displayed in the plugin deletion confirmation (#8784) – Fabian Braun
Fix migration 0044 failing on SQLite when versioning was installed (#8777, #8779) – Fabian Braun
Fix the language column in the page tree ignoring multi-hyphen language codes such as
de-x-l(#8781) – Fabian BraunFix the wrong
welcome.jspath (#8761) – Fabian BraunAdd PostgreSQL 15 minimum version coverage for Django 6.1 to CI (#8774) – Atiqur Rahman
Statistics¶
This release includes 16 changelog entries, created with the help of the following contributors (in alphabetical order):
Atiqur Rahman (1 changelog entry)
Fabian Braun (15 changelog entries)
With the review help of the following contributors:
Fabian Braun
Mark Walker
Vinit Kumar
Thanks to all contributors for their efforts!