diff --git a/wagtail/contrib/modeladmin/forms.py b/wagtail/contrib/modeladmin/forms.py index 92feab81f0..be5431a56f 100644 --- a/wagtail/contrib/modeladmin/forms.py +++ b/wagtail/contrib/modeladmin/forms.py @@ -1,5 +1,4 @@ from django import forms -from django.utils.safestring import mark_safe from django.utils.translation import gettext as _ from wagtail.models import Page @@ -12,7 +11,7 @@ class PageChoiceField(forms.ModelChoiceField): obj.get_ancestors(inclusive=True).exclude(depth=1).specific(defer=True) ): bits.append(ancestor.get_admin_display_title()) - return mark_safe(''.join(bits)) + return " | ".join(bits) class ParentChooserForm(forms.Form): diff --git a/wagtail/contrib/modeladmin/tests/test_page_modeladmin.py b/wagtail/contrib/modeladmin/tests/test_page_modeladmin.py index e09f2f4ab7..8c589cadd8 100644 --- a/wagtail/contrib/modeladmin/tests/test_page_modeladmin.py +++ b/wagtail/contrib/modeladmin/tests/test_page_modeladmin.py @@ -306,6 +306,21 @@ class TestChooseParentView(WagtailTestUtils, TestCase): """ self.assertContains(response, expected, html=True) + def test_page_title_html_escaping(self): + homepage = Page.objects.get(url_path="/home/") + business_index = BusinessIndex( + title="Title with ", + ) + homepage.add_child(instance=business_index) + + response = self.client.get("/admin/tests/businesschild/choose_parent/") + + self.assertEqual(response.status_code, 200) + self.assertNotContains(response, "Title with ") + self.assertContains( + response, "Title with <script>alert('XSS')</script>" + ) + class TestChooseParentViewForNonSuperuser(WagtailTestUtils, TestCase): fixtures = ["test_specific.json"]