Impact
A stored cross-site scripting (XSS) vulnerability exists on ModelAdmin views within the Wagtail admin interface. A user with a limited-permission editor account for the Wagtail admin could potentially craft pages and documents that, when viewed by a user with higher privileges, could perform actions with that user's credentials. The vulnerability is not exploitable by an ordinary site visitor without access to the Wagtail admin, and only affects sites with ModelAdmin enabled.
- For page, the vulnerability is in the "Choose a parent page" ModelAdmin view (ChooseParentView), available when managing pages via ModelAdmin. - For documents, the vulnerability is in the ModelAdmin Inspect view (InspectView) when displaying document fields.
Patches
Patched versions have been released as Wagtail 4.1.4 (for the LTS 4.1 branch) and Wagtail 4.2.2 (for the current 4.2 branch).
Workarounds
Site owners who are unable to upgrade to the new versions can disable or override the corresponding functionality.
ChooseParentView
For ChooseParentView:
- Disable ModelAdmin for all page models. - Or provide a custom view via chooseparentviewclass, with the custom view overriding the getform method.
One of those steps need to be applied for every ModelAdmin class hooked into Wagtail where the model is a Wagtail Page or sub-class. Here is an example of implementing the custom ChooseParentView with patched HTML escaping:
python from django import forms from django.utils.translation import gettext as from wagtail.contrib.modeladmin.views import ChooseParentView from wagtail.contrib.modeladmin.forms import ParentChooserForm
class PatchedPageChoiceField(forms.ModelChoiceField): """PageChoiceField with plain-text breadcrumbs to patch stored XSS.""" def labelfrominstance(self, obj): bits = [] for ancestor in ( obj.getancestors(inclusive=True).exclude(depth=1).specific(defer=True) ): bits.append(ancestor.getadmindisplaytitle()) return ' | '.join(bits)
class PatchedParentChooserForm(ParentChooserForm): """ParentChooserForm with custom parentpage to patch stored XSS.""" parentpage = PatchedPageChoiceField( label=("Parent page"), required=True, emptylabel=None, queryset=Page.objects.none(), widget=forms.RadioSelect(), )
class PatchedChooseParentView(ChooseParentView): """ChooseParentView with custom getform patch stored XSS.""" def getform(self, request): parents = self.permissionhelper.getvalidparentpages(request.user) return PatchedParentChooserForm(parents, request.POST or None)
InspectView
For InspectView:
- Remove inspectviewenabled=True or set it to False to disable the view. - Or use inspectviewfields or inspectviewfieldsexclude to prevent displaying document fields in the views. - Or provide a custom view via inspectviewclass, with the custom view overriding the getdocumentfielddisplay method.
One of those steps need to be applied for every ModelAdmin class hooked into Wagtail where inspectviewenabled=True. Here is an example of implementing the custom InspectView with patched HTML escaping:
python from django.template.defaultfilters import filesizeformat from django.utils.html import formathtml from wagtail.contrib.modeladmin.views import InspectView
class PatchedInspectView(InspectView): """InspectView with override to patch stored XSS vulnerability.""" def getdocumentfielddisplay(self, fieldname, field): """Render a link to a document""" document = getattr(self.instance, fieldname) if document: return formathtml( '<a href="{}">{} <span class="meta">({}, {})</span></a>', document.url, document.title, document.fileextension.upper(), filesizeformat(document.file.size), ) return self.modeladmin.getemptyvaluedisplay(fieldname)
Impact
A memory exhaustion bug exists in Wagtail's handling of uploaded images and documents. For both images and documents, files are loaded into memory during upload for additional processing. A user with access to upload images or documents through the Wagtail admin interface could upload a file so large that it results in a crash or denial of service.
The vulnerability is not exploitable by an ordinary site visitor without access to the Wagtail admin. It can only be exploited by admin users with permission to upload images or documents.
Image uploads are restricted to 10MB by default, however this validation only happens on the frontend and on the backend after the vulnerable code.
Patches
Patched versions have been released as Wagtail 4.1.4 (for the LTS 4.1 branch) and Wagtail 4.2.2 (for the current 4.2 branch).
Workarounds
Site owners who are unable to upgrade to the new versions are encouraged to add extra protections outside of Wagtail to limit the size of uploaded files. Exactly how this is done will vary based on your hosting environment, but here are a few references for common setups:
- Nginx: clientmaxbodysize - Apache: LimitRequestBody - Cloudflare: Already imposes a limit of 100MB - 500MB depending on plan - CloudFront: SizeConstraint - Traefik: traefik.http.middlewares.limit.buffering.maxRequestBodyBytes
The changes themselves are deep inside Wagtail, making patching incredibly difficult.
Impact
A user with a limited-permission editor account for the Wagtail admin can make a direct URL request to the admin view that handles bulk actions on user accounts. While authentication rules prevent the user from making any changes, the error message discloses the display names of user accounts, and by modifying URL parameters, the user can retrieve the display name for any user. The vulnerability is not exploitable by an ordinary site visitor without access to the Wagtail admin.
Patches Patched versions have been released as Wagtail 4.1.9 (LTS), 5.0.5 and 5.1.3. The fix is also included in Release Candidate 1 of the forthcoming Wagtail 5.2 release.
Workarounds None.
Acknowledgements Many thanks to @quyenheu for reporting this issue.
For more information If you have any questions or comments about this advisory:
Visit Wagtail's support channels Email us at security@wagtail.org (view our security policy for more information).
End of life: 8/1/2023, End of support: 5/2/2023, Latest version: 4.2.4
End of life: 8/1/2023, End of support: 5/2/2023, Latest version: 4.2.4