From 0f44a2ad4e170882dbe6b9d95dba6c36e4e181cf Mon Sep 17 00:00:00 2001 From: Mira Date: Fri, 23 Aug 2024 14:41:25 +0200 Subject: [PATCH] Escape HTML in placeholder samples in mail preview (#4413) CVE-2024-8113 --- src/pretix/base/forms/widgets.py | 3 ++- src/pretix/control/views/event.py | 5 +++-- src/pretix/control/views/vouchers.py | 4 ++-- src/pretix/plugins/sendmail/views.py | 7 ++++--- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/pretix/base/forms/widgets.py b/src/pretix/base/forms/widgets.py index 917b339d3..69620b201 100644 --- a/src/pretix/base/forms/widgets.py +++ b/src/pretix/base/forms/widgets.py @@ -38,6 +38,7 @@ from datetime import datetime from django import forms from django.utils.formats import get_format from django.utils.functional import lazy +from django.utils.html import escape from django.utils.timezone import get_current_timezone, now from django.utils.translation import gettext_lazy as _ @@ -64,7 +65,7 @@ def format_placeholders_help_text(placeholders, event=None): placeholders = [(k, v.render_sample(event) if event else v) for k, v in placeholders.items()] placeholders.sort(key=lambda x: x[0]) phs = [ - '' % (_("Sample: %s") % v if v else "", k) + '' % (escape(_("Sample: %s") % v) if v else "", escape(k)) for k, v in placeholders ] return _('Available placeholders: {list}').format( diff --git a/src/pretix/control/views/event.py b/src/pretix/control/views/event.py index 5eafa1343..1b41dd982 100644 --- a/src/pretix/control/views/event.py +++ b/src/pretix/control/views/event.py @@ -62,6 +62,7 @@ from django.http import ( from django.shortcuts import get_object_or_404, redirect from django.urls import reverse from django.utils.functional import cached_property +from django.utils.html import escape from django.utils.http import url_has_allowed_host_and_scheme from django.utils.timezone import now from django.utils.translation import gettext, gettext_lazy as _, gettext_noop @@ -726,7 +727,7 @@ class MailSettingsPreview(EventPermissionRequiredMixin, View): else: ctx[p.identifier] = '{}'.format( _('This value will be replaced based on dynamic parameters.'), - s + escape(s) ) return ctx @@ -776,7 +777,7 @@ class MailSettingsRendererPreview(MailSettingsPreview): def placeholders(self, item): ctx = {} for p in get_available_placeholders(self.request.event, MailSettingsForm.base_context[item]).values(): - ctx[p.identifier] = str(p.render_sample(self.request.event)) + ctx[p.identifier] = escape(str(p.render_sample(self.request.event))) return ctx def get(self, request, *args, **kwargs): diff --git a/src/pretix/control/views/vouchers.py b/src/pretix/control/views/vouchers.py index 640dfbe1b..688c93f29 100644 --- a/src/pretix/control/views/vouchers.py +++ b/src/pretix/control/views/vouchers.py @@ -50,7 +50,7 @@ from django.http import ( from django.shortcuts import redirect, render from django.urls import resolve, reverse from django.utils.functional import cached_property -from django.utils.html import format_html +from django.utils.html import format_html, escape from django.utils.safestring import mark_safe from django.utils.timezone import now from django.utils.translation import gettext_lazy as _ @@ -562,7 +562,7 @@ class VoucherBulkMailPreview(EventPermissionRequiredMixin, View): else: ctx[p.identifier] = '{}'.format( _('This value will be replaced based on dynamic parameters.'), - s + escape(s) ) return self.SafeDict(ctx) diff --git a/src/pretix/plugins/sendmail/views.py b/src/pretix/plugins/sendmail/views.py index 30d570ef9..27266556b 100644 --- a/src/pretix/plugins/sendmail/views.py +++ b/src/pretix/plugins/sendmail/views.py @@ -46,6 +46,7 @@ from django.shortcuts import get_object_or_404, redirect from django.template.loader import get_template from django.urls import reverse from django.utils.functional import cached_property +from django.utils.html import escape from django.utils.timezone import now from django.utils.translation import gettext_lazy as _, ngettext from django.views.generic import DeleteView, FormView, ListView, TemplateView @@ -193,7 +194,7 @@ class BaseSenderView(EventPermissionRequiredMixin, FormView): for k, v in get_available_placeholders(self.request.event, self.context_parameters).items(): context_dict[k] = '{}'.format( _('This value will be replaced based on dynamic parameters.'), - v.render_sample(self.request.event) + escape(v.render_sample(self.request.event)) ) subject = bleach.clean(form.cleaned_data['subject'].localize(l), tags=[]) @@ -608,7 +609,7 @@ class CreateRule(EventPermissionRequiredMixin, CreateView): 'position_or_address']).items(): context_dict[k] = '{}'.format( _('This value will be replaced based on dynamic parameters.'), - v.render_sample(self.request.event) + escape(v.render_sample(self.request.event)) ) subject = bleach.clean(form.cleaned_data['subject'].localize(l), tags=[]) @@ -684,7 +685,7 @@ class UpdateRule(EventPermissionRequiredMixin, UpdateView): for k, v in get_available_placeholders(self.request.event, ['event', 'order', 'position_or_address']).items(): placeholders[k] = '{}'.format( _('This value will be replaced based on dynamic parameters.'), - v.render_sample(self.request.event) + escape(v.render_sample(self.request.event)) ) subject = bleach.clean(self.object.subject.localize(lang), tags=[])