Wagtail: Improper escaping of HTML (Cross-site Scripting) in simple_translation admin interface
Description
Wagtail is an open source content management system built on Django. Prior to versions 6.3.8, 7.0.6, 7.2.3, and 7.3.1, a stored cross-site scripting (XSS) vulnerability exists on confirmation messages within the wagtail.contrib.simple_translation module. A user with access to the Wagtail admin area may create a page with a specially-crafted title which, when another user performs the "Translate" action, causes arbitrary JavaScript code to run. This could lead to performing actions with that user's credentials. The vulnerability is not exploitable by an ordinary site visitor without access to the Wagtail admin. This issue has been patched in versions 6.3.8, 7.0.6, 7.2.3, and 7.3.1.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
wagtailPyPI | < 6.3.8 | 6.3.8 |
wagtailPyPI | >= 6.4rc1, < 7.0.6 | 7.0.6 |
wagtailPyPI | >= 7.1rc1, < 7.2.3 | 7.2.3 |
wagtailPyPI | >= 7.3rc1, < 7.3.1 | 7.3.1 |
Affected products
1Patches
4ba70244d376aEnforce HTML escaping of all confirmation / warning / error messages
4 files changed · +81 −12
wagtail/admin/templates/wagtailadmin/base.html+1 −1 modified@@ -25,7 +25,7 @@ {% else %} {% icon name=level_tag classname="messages-icon" %} {% endif %} - {{ message|safe }} + {{ message }} {% if level_tag == "error" %} {# Show a button to focus the first field/response error if available. #} <button
wagtail/admin/views/account.py+1 −1 modified@@ -2,7 +2,6 @@ from functools import cached_property from django.conf import settings -from django.contrib import messages from django.contrib.auth import update_session_auth_hash from django.contrib.auth import views as auth_views from django.db import transaction @@ -19,6 +18,7 @@ from django.views.generic.base import TemplateView from wagtail import hooks +from wagtail.admin import messages from wagtail.admin.forms.account import ( AvatarPreferencesForm, LocalePreferencesForm,
wagtail/contrib/simple_translation/tests/test_views.py+78 −9 modified@@ -179,8 +179,24 @@ def test_submit_page_translation_view_test_post_single_locale(self): ) self.assertIn( - "The page 'Blog' was successfully created in German", - [msg.message for msg in response.context["messages"]], + "The page 'Blog' was successfully created in German", + [msg.message.strip() for msg in response.context["messages"]], + ) + + def test_submit_page_translation_view_escapes_title_in_confirmation_message(self): + self.en_blog_index.title = "<img src=x onerror=alert(4242)>" + self.en_blog_index.draft_title = self.en_blog_index.title + self.en_blog_index.save() + url = reverse( + "simple_translation:submit_page_translation", args=(self.en_blog_index.id,) + ) + de = Locale.objects.get(language_code="de").id + data = {"locales": [de], "include_subtree": True} + self.login() + response = self.client.post(url, data, follow=True) + self.assertContains( + response, + "The page '<img src=x onerror=alert(4242)>' was successfully created in German", ) def test_submit_page_translation_view_test_post_multiple_locales(self): @@ -208,10 +224,30 @@ def test_submit_page_translation_view_test_post_multiple_locales(self): assert response.url == f"/admin/pages/{self.en_blog_index.get_parent().id}/" response = self.client.get(response.url) # follow the redirect - assert [msg.message for msg in response.context["messages"]] == [ - "The page 'Blog' was successfully created in 2 locales" + assert [msg.message.strip() for msg in response.context["messages"]] == [ + "The page 'Blog' was successfully created in 2 locales" ] + def test_submit_page_translation_view_multiple_locales_escapes_title_in_confirmation_message( + self, + ): + self.en_blog_index.title = "<img src=x onerror=alert(4242)>" + self.en_blog_index.draft_title = self.en_blog_index.title + self.en_blog_index.save() + + url = reverse( + "simple_translation:submit_page_translation", args=(self.en_blog_index.id,) + ) + de = Locale.objects.get(language_code="de").id + fr = Locale.objects.get(language_code="fr").id + data = {"locales": [de, fr], "include_subtree": True} + self.login() + response = self.client.post(url, data, follow=True) + self.assertContains( + response, + "The page '<img src=x onerror=alert(4242)>' was successfully created in 2 locales", + ) + @override_settings( LANGUAGES=[ @@ -359,7 +395,7 @@ def test_submit_snippet_translation_view_test_post_single_locale(self): translated_snippet = self.en_snippet.get_translation(self.de_locale.id) self.assertRedirects(response, self.get_snippet_url("edit", translated_snippet)) - self.assertContains(response, "It's edited", count=1) + self.assertContains(response, "It's edited") self.assertContains(response, '<h3 id="status-sidebar-german"', count=1) self.assertContains( response, @@ -372,8 +408,24 @@ def test_submit_snippet_translation_view_test_post_single_locale(self): ) self.assertEqual( - [msg.message for msg in response.context["messages"]], - ["Successfully created German for full-featured snippet 'It's edited'"], + [msg.message.strip() for msg in response.context["messages"]], + [ + "Successfully created German for full-featured snippet 'It's edited'" + ], + ) + + def test_submit_snippet_translation_view_escapes_title_in_confirmation_message( + self, + ): + self.en_snippet.text = "<img src=x onerror=alert(4242)>" + self.en_snippet.save_revision() + + data = {"locales": [self.de_locale.id], "include_subtree": True} + response = self.client.post(self.get_submit_url(), data, follow=True) + + self.assertContains( + response, + "Successfully created German for full-featured snippet '<img src=x onerror=alert(4242)>'", ) def test_submit_snippet_translation_view_test_post_multiple_locales(self): @@ -387,8 +439,25 @@ def test_submit_snippet_translation_view_test_post_multiple_locales(self): response = self.client.get(response.url) # follow the redirect self.assertEqual( - [msg.message for msg in response.context["messages"]], - ["Successfully created 2 locales for full-featured snippet 'It's edited'"], + [msg.message.strip() for msg in response.context["messages"]], + [ + "Successfully created 2 locales for full-featured snippet 'It's edited'" + ], + ) + + def test_submit_snippet_translation_view_multiple_locales_escapes_title_in_confirmation_message( + self, + ): + self.en_snippet.text = "<img src=x onerror=alert(4242)>" + self.en_snippet.save_revision() + + url = self.get_submit_url() + data = {"locales": [self.de_locale.id, self.fr_locale.id]} + response = self.client.post(url, data, follow=True) + + self.assertContains( + response, + "Successfully created 2 locales for full-featured snippet '<img src=x onerror=alert(4242)>'", )
wagtail/contrib/simple_translation/views.py+1 −1 modified@@ -1,4 +1,3 @@ -from django.contrib import messages from django.contrib.admin.utils import unquote from django.core.exceptions import PermissionDenied from django.db import transaction @@ -11,6 +10,7 @@ from django.views.generic.detail import SingleObjectMixin from wagtail.actions.copy_for_translation import CopyPageForTranslationAction +from wagtail.admin import messages from wagtail.models import DraftStateMixin, Page, TranslatableMixin from wagtail.snippets.views.snippets import get_snippet_model_from_url_params
1c6f2effed68Enforce HTML escaping of all confirmation / warning / error messages
4 files changed · +81 −12
wagtail/admin/templates/wagtailadmin/base.html+1 −1 modified@@ -25,7 +25,7 @@ {% else %} {% icon name=level_tag classname="messages-icon" %} {% endif %} - {{ message|safe }} + {{ message }} {% if level_tag == "error" %} {# Show a button to focus the first field/response error if available. #} <button
wagtail/admin/views/account.py+1 −1 modified@@ -2,7 +2,6 @@ from functools import cached_property from django.conf import settings -from django.contrib import messages from django.contrib.auth import update_session_auth_hash from django.contrib.auth import views as auth_views from django.db import transaction @@ -19,6 +18,7 @@ from django.views.generic.base import TemplateView from wagtail import hooks +from wagtail.admin import messages from wagtail.admin.forms.account import ( AvatarPreferencesForm, LocalePreferencesForm,
wagtail/contrib/simple_translation/tests/test_views.py+78 −9 modified@@ -179,8 +179,24 @@ def test_submit_page_translation_view_test_post_single_locale(self): ) self.assertIn( - "The page 'Blog' was successfully created in German", - [msg.message for msg in response.context["messages"]], + "The page 'Blog' was successfully created in German", + [msg.message.strip() for msg in response.context["messages"]], + ) + + def test_submit_page_translation_view_escapes_title_in_confirmation_message(self): + self.en_blog_index.title = "<img src=x onerror=alert(4242)>" + self.en_blog_index.draft_title = self.en_blog_index.title + self.en_blog_index.save() + url = reverse( + "simple_translation:submit_page_translation", args=(self.en_blog_index.id,) + ) + de = Locale.objects.get(language_code="de").id + data = {"locales": [de], "include_subtree": True} + self.login() + response = self.client.post(url, data, follow=True) + self.assertContains( + response, + "The page '<img src=x onerror=alert(4242)>' was successfully created in German", ) def test_submit_page_translation_view_test_post_multiple_locales(self): @@ -208,10 +224,30 @@ def test_submit_page_translation_view_test_post_multiple_locales(self): assert response.url == f"/admin/pages/{self.en_blog_index.get_parent().id}/" response = self.client.get(response.url) # follow the redirect - assert [msg.message for msg in response.context["messages"]] == [ - "The page 'Blog' was successfully created in 2 locales" + assert [msg.message.strip() for msg in response.context["messages"]] == [ + "The page 'Blog' was successfully created in 2 locales" ] + def test_submit_page_translation_view_multiple_locales_escapes_title_in_confirmation_message( + self, + ): + self.en_blog_index.title = "<img src=x onerror=alert(4242)>" + self.en_blog_index.draft_title = self.en_blog_index.title + self.en_blog_index.save() + + url = reverse( + "simple_translation:submit_page_translation", args=(self.en_blog_index.id,) + ) + de = Locale.objects.get(language_code="de").id + fr = Locale.objects.get(language_code="fr").id + data = {"locales": [de, fr], "include_subtree": True} + self.login() + response = self.client.post(url, data, follow=True) + self.assertContains( + response, + "The page '<img src=x onerror=alert(4242)>' was successfully created in 2 locales", + ) + @override_settings( LANGUAGES=[ @@ -359,7 +395,7 @@ def test_submit_snippet_translation_view_test_post_single_locale(self): translated_snippet = self.en_snippet.get_translation(self.de_locale.id) self.assertRedirects(response, self.get_snippet_url("edit", translated_snippet)) - self.assertContains(response, "It's edited", count=1) + self.assertContains(response, "It's edited") self.assertContains(response, '<h3 id="status-sidebar-german"', count=1) self.assertContains( response, @@ -372,8 +408,24 @@ def test_submit_snippet_translation_view_test_post_single_locale(self): ) self.assertEqual( - [msg.message for msg in response.context["messages"]], - ["Successfully created German for full-featured snippet 'It's edited'"], + [msg.message.strip() for msg in response.context["messages"]], + [ + "Successfully created German for full-featured snippet 'It's edited'" + ], + ) + + def test_submit_snippet_translation_view_escapes_title_in_confirmation_message( + self, + ): + self.en_snippet.text = "<img src=x onerror=alert(4242)>" + self.en_snippet.save_revision() + + data = {"locales": [self.de_locale.id], "include_subtree": True} + response = self.client.post(self.get_submit_url(), data, follow=True) + + self.assertContains( + response, + "Successfully created German for full-featured snippet '<img src=x onerror=alert(4242)>'", ) def test_submit_snippet_translation_view_test_post_multiple_locales(self): @@ -387,8 +439,25 @@ def test_submit_snippet_translation_view_test_post_multiple_locales(self): response = self.client.get(response.url) # follow the redirect self.assertEqual( - [msg.message for msg in response.context["messages"]], - ["Successfully created 2 locales for full-featured snippet 'It's edited'"], + [msg.message.strip() for msg in response.context["messages"]], + [ + "Successfully created 2 locales for full-featured snippet 'It's edited'" + ], + ) + + def test_submit_snippet_translation_view_multiple_locales_escapes_title_in_confirmation_message( + self, + ): + self.en_snippet.text = "<img src=x onerror=alert(4242)>" + self.en_snippet.save_revision() + + url = self.get_submit_url() + data = {"locales": [self.de_locale.id, self.fr_locale.id]} + response = self.client.post(url, data, follow=True) + + self.assertContains( + response, + "Successfully created 2 locales for full-featured snippet '<img src=x onerror=alert(4242)>'", )
wagtail/contrib/simple_translation/views.py+1 −1 modified@@ -1,4 +1,3 @@ -from django.contrib import messages from django.contrib.admin.utils import unquote from django.core.exceptions import PermissionDenied from django.db import transaction @@ -11,6 +10,7 @@ from django.views.generic.detail import SingleObjectMixin from wagtail.actions.copy_for_translation import CopyPageForTranslationAction +from wagtail.admin import messages from wagtail.models import DraftStateMixin, Page, TranslatableMixin from wagtail.snippets.views.snippets import get_snippet_model_from_url_params
d8c5900982dfEnforce HTML escaping of all confirmation / warning / error messages
4 files changed · +81 −12
wagtail/admin/templates/wagtailadmin/base.html+1 −1 modified@@ -25,7 +25,7 @@ {% else %} {% icon name=level_tag classname="messages-icon" %} {% endif %} - {{ message|safe }} + {{ message }} </li> {% endfor %} {% endif %}
wagtail/admin/views/account.py+1 −1 modified@@ -2,7 +2,6 @@ from functools import cached_property from django.conf import settings -from django.contrib import messages from django.contrib.auth import update_session_auth_hash from django.contrib.auth import views as auth_views from django.db import transaction @@ -19,6 +18,7 @@ from django.views.generic.base import TemplateView from wagtail import hooks +from wagtail.admin import messages from wagtail.admin.forms.account import ( AvatarPreferencesForm, LocalePreferencesForm,
wagtail/contrib/simple_translation/tests/test_views.py+78 −9 modified@@ -179,8 +179,24 @@ def test_submit_page_translation_view_test_post_single_locale(self): ) self.assertIn( - "The page 'Blog' was successfully created in German", - [msg.message for msg in response.context["messages"]], + "The page 'Blog' was successfully created in German", + [msg.message.strip() for msg in response.context["messages"]], + ) + + def test_submit_page_translation_view_escapes_title_in_confirmation_message(self): + self.en_blog_index.title = "<img src=x onerror=alert(4242)>" + self.en_blog_index.draft_title = self.en_blog_index.title + self.en_blog_index.save() + url = reverse( + "simple_translation:submit_page_translation", args=(self.en_blog_index.id,) + ) + de = Locale.objects.get(language_code="de").id + data = {"locales": [de], "include_subtree": True} + self.login() + response = self.client.post(url, data, follow=True) + self.assertContains( + response, + "The page '<img src=x onerror=alert(4242)>' was successfully created in German", ) def test_submit_page_translation_view_test_post_multiple_locales(self): @@ -208,10 +224,30 @@ def test_submit_page_translation_view_test_post_multiple_locales(self): assert response.url == f"/admin/pages/{self.en_blog_index.get_parent().id}/" response = self.client.get(response.url) # follow the redirect - assert [msg.message for msg in response.context["messages"]] == [ - "The page 'Blog' was successfully created in 2 locales" + assert [msg.message.strip() for msg in response.context["messages"]] == [ + "The page 'Blog' was successfully created in 2 locales" ] + def test_submit_page_translation_view_multiple_locales_escapes_title_in_confirmation_message( + self, + ): + self.en_blog_index.title = "<img src=x onerror=alert(4242)>" + self.en_blog_index.draft_title = self.en_blog_index.title + self.en_blog_index.save() + + url = reverse( + "simple_translation:submit_page_translation", args=(self.en_blog_index.id,) + ) + de = Locale.objects.get(language_code="de").id + fr = Locale.objects.get(language_code="fr").id + data = {"locales": [de, fr], "include_subtree": True} + self.login() + response = self.client.post(url, data, follow=True) + self.assertContains( + response, + "The page '<img src=x onerror=alert(4242)>' was successfully created in 2 locales", + ) + @override_settings( LANGUAGES=[ @@ -359,7 +395,7 @@ def test_submit_snippet_translation_view_test_post_single_locale(self): translated_snippet = self.en_snippet.get_translation(self.de_locale.id) self.assertRedirects(response, self.get_snippet_url("edit", translated_snippet)) - self.assertContains(response, "It's edited", count=1) + self.assertContains(response, "It's edited") self.assertContains(response, '<h3 id="status-sidebar-german"', count=1) self.assertContains( response, @@ -372,8 +408,24 @@ def test_submit_snippet_translation_view_test_post_single_locale(self): ) self.assertEqual( - [msg.message for msg in response.context["messages"]], - ["Successfully created German for full-featured snippet 'It's edited'"], + [msg.message.strip() for msg in response.context["messages"]], + [ + "Successfully created German for full-featured snippet 'It's edited'" + ], + ) + + def test_submit_snippet_translation_view_escapes_title_in_confirmation_message( + self, + ): + self.en_snippet.text = "<img src=x onerror=alert(4242)>" + self.en_snippet.save_revision() + + data = {"locales": [self.de_locale.id], "include_subtree": True} + response = self.client.post(self.get_submit_url(), data, follow=True) + + self.assertContains( + response, + "Successfully created German for full-featured snippet '<img src=x onerror=alert(4242)>'", ) def test_submit_snippet_translation_view_test_post_multiple_locales(self): @@ -387,8 +439,25 @@ def test_submit_snippet_translation_view_test_post_multiple_locales(self): response = self.client.get(response.url) # follow the redirect self.assertEqual( - [msg.message for msg in response.context["messages"]], - ["Successfully created 2 locales for full-featured snippet 'It's edited'"], + [msg.message.strip() for msg in response.context["messages"]], + [ + "Successfully created 2 locales for full-featured snippet 'It's edited'" + ], + ) + + def test_submit_snippet_translation_view_multiple_locales_escapes_title_in_confirmation_message( + self, + ): + self.en_snippet.text = "<img src=x onerror=alert(4242)>" + self.en_snippet.save_revision() + + url = self.get_submit_url() + data = {"locales": [self.de_locale.id, self.fr_locale.id]} + response = self.client.post(url, data, follow=True) + + self.assertContains( + response, + "Successfully created 2 locales for full-featured snippet '<img src=x onerror=alert(4242)>'", )
wagtail/contrib/simple_translation/views.py+1 −1 modified@@ -1,4 +1,3 @@ -from django.contrib import messages from django.contrib.admin.utils import unquote from django.core.exceptions import PermissionDenied from django.db import transaction @@ -11,6 +10,7 @@ from django.views.generic.detail import SingleObjectMixin from wagtail.actions.copy_for_translation import CopyPageForTranslationAction +from wagtail.admin import messages from wagtail.models import DraftStateMixin, Page, TranslatableMixin from wagtail.snippets.views.snippets import get_snippet_model_from_url_params
ee39d39deeb7Enforce HTML escaping of all confirmation / warning / error messages
4 files changed · +81 −12
wagtail/admin/templates/wagtailadmin/base.html+1 −1 modified@@ -25,7 +25,7 @@ {% else %} {% icon name=level_tag classname="messages-icon" %} {% endif %} - {{ message|safe }} + {{ message }} </li> {% endfor %} {% endif %}
wagtail/admin/views/account.py+1 −1 modified@@ -2,7 +2,6 @@ from functools import cached_property from django.conf import settings -from django.contrib import messages from django.contrib.auth import update_session_auth_hash from django.contrib.auth import views as auth_views from django.db import transaction @@ -19,6 +18,7 @@ from django.views.generic.base import TemplateView from wagtail import hooks +from wagtail.admin import messages from wagtail.admin.forms.account import ( AvatarPreferencesForm, LocalePreferencesForm,
wagtail/contrib/simple_translation/tests/test_views.py+78 −9 modified@@ -179,8 +179,24 @@ def test_submit_page_translation_view_test_post_single_locale(self): ) self.assertIn( - "The page 'Blog' was successfully created in German", - [msg.message for msg in response.context["messages"]], + "The page 'Blog' was successfully created in German", + [msg.message.strip() for msg in response.context["messages"]], + ) + + def test_submit_page_translation_view_escapes_title_in_confirmation_message(self): + self.en_blog_index.title = "<img src=x onerror=alert(4242)>" + self.en_blog_index.draft_title = self.en_blog_index.title + self.en_blog_index.save() + url = reverse( + "simple_translation:submit_page_translation", args=(self.en_blog_index.id,) + ) + de = Locale.objects.get(language_code="de").id + data = {"locales": [de], "include_subtree": True} + self.login() + response = self.client.post(url, data, follow=True) + self.assertContains( + response, + "The page '<img src=x onerror=alert(4242)>' was successfully created in German", ) def test_submit_page_translation_view_test_post_multiple_locales(self): @@ -208,10 +224,30 @@ def test_submit_page_translation_view_test_post_multiple_locales(self): assert response.url == f"/admin/pages/{self.en_blog_index.get_parent().id}/" response = self.client.get(response.url) # follow the redirect - assert [msg.message for msg in response.context["messages"]] == [ - "The page 'Blog' was successfully created in 2 locales" + assert [msg.message.strip() for msg in response.context["messages"]] == [ + "The page 'Blog' was successfully created in 2 locales" ] + def test_submit_page_translation_view_multiple_locales_escapes_title_in_confirmation_message( + self, + ): + self.en_blog_index.title = "<img src=x onerror=alert(4242)>" + self.en_blog_index.draft_title = self.en_blog_index.title + self.en_blog_index.save() + + url = reverse( + "simple_translation:submit_page_translation", args=(self.en_blog_index.id,) + ) + de = Locale.objects.get(language_code="de").id + fr = Locale.objects.get(language_code="fr").id + data = {"locales": [de, fr], "include_subtree": True} + self.login() + response = self.client.post(url, data, follow=True) + self.assertContains( + response, + "The page '<img src=x onerror=alert(4242)>' was successfully created in 2 locales", + ) + @override_settings( LANGUAGES=[ @@ -359,7 +395,7 @@ def test_submit_snippet_translation_view_test_post_single_locale(self): translated_snippet = self.en_snippet.get_translation(self.de_locale.id) self.assertRedirects(response, self.get_snippet_url("edit", translated_snippet)) - self.assertContains(response, "It's edited", count=1) + self.assertContains(response, "It's edited") self.assertContains(response, '<h3 id="status-sidebar-german"', count=1) self.assertContains( response, @@ -372,8 +408,24 @@ def test_submit_snippet_translation_view_test_post_single_locale(self): ) self.assertEqual( - [msg.message for msg in response.context["messages"]], - ["Successfully created German for full-featured snippet 'It's edited'"], + [msg.message.strip() for msg in response.context["messages"]], + [ + "Successfully created German for full-featured snippet 'It's edited'" + ], + ) + + def test_submit_snippet_translation_view_escapes_title_in_confirmation_message( + self, + ): + self.en_snippet.text = "<img src=x onerror=alert(4242)>" + self.en_snippet.save_revision() + + data = {"locales": [self.de_locale.id], "include_subtree": True} + response = self.client.post(self.get_submit_url(), data, follow=True) + + self.assertContains( + response, + "Successfully created German for full-featured snippet '<img src=x onerror=alert(4242)>'", ) def test_submit_snippet_translation_view_test_post_multiple_locales(self): @@ -387,8 +439,25 @@ def test_submit_snippet_translation_view_test_post_multiple_locales(self): response = self.client.get(response.url) # follow the redirect self.assertEqual( - [msg.message for msg in response.context["messages"]], - ["Successfully created 2 locales for full-featured snippet 'It's edited'"], + [msg.message.strip() for msg in response.context["messages"]], + [ + "Successfully created 2 locales for full-featured snippet 'It's edited'" + ], + ) + + def test_submit_snippet_translation_view_multiple_locales_escapes_title_in_confirmation_message( + self, + ): + self.en_snippet.text = "<img src=x onerror=alert(4242)>" + self.en_snippet.save_revision() + + url = self.get_submit_url() + data = {"locales": [self.de_locale.id, self.fr_locale.id]} + response = self.client.post(url, data, follow=True) + + self.assertContains( + response, + "Successfully created 2 locales for full-featured snippet '<img src=x onerror=alert(4242)>'", )
wagtail/contrib/simple_translation/views.py+1 −1 modified@@ -1,4 +1,3 @@ -from django.contrib import messages from django.contrib.admin.utils import unquote from django.core.exceptions import PermissionDenied from django.db import transaction @@ -11,6 +10,7 @@ from django.views.generic.detail import SingleObjectMixin from wagtail.actions.copy_for_translation import CopyPageForTranslationAction +from wagtail.admin import messages from wagtail.models import DraftStateMixin, Page, TranslatableMixin from wagtail.snippets.views.snippets import get_snippet_model_from_url_params
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
11- github.com/advisories/GHSA-p4v8-rw59-93cqghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2026-28223ghsaADVISORY
- github.com/wagtail/wagtail/commit/1c6f2effed68f4ccad6fbd07987e03641505f863ghsax_refsource_MISCWEB
- github.com/wagtail/wagtail/commit/ba70244d376a7b1bd180ded03e827917ff410c19ghsax_refsource_MISCWEB
- github.com/wagtail/wagtail/commit/d8c5900982df8ed5938ad993aa9ff69cda50f80cghsax_refsource_MISCWEB
- github.com/wagtail/wagtail/commit/ee39d39deeb7f250fe886417b24802d7e05b1143ghsax_refsource_MISCWEB
- github.com/wagtail/wagtail/releases/tag/v6.3.8ghsax_refsource_MISCWEB
- github.com/wagtail/wagtail/releases/tag/v7.0.6ghsax_refsource_MISCWEB
- github.com/wagtail/wagtail/releases/tag/v7.2.3ghsax_refsource_MISCWEB
- github.com/wagtail/wagtail/releases/tag/v7.3.1ghsax_refsource_MISCWEB
- github.com/wagtail/wagtail/security/advisories/GHSA-p4v8-rw59-93cqghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.