mirror of
https://github.com/pretix/pretix.git
synced 2026-09-30 19:04:43 +00:00
[SECURITY] Fix checkout validation bypass (CVE-2026-101266, Z#23245008)
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
#
|
||||
from urllib.parse import quote, urlencode
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.http import Http404
|
||||
from django.utils.decorators import method_decorator
|
||||
@@ -29,6 +30,7 @@ from django.views.generic import View
|
||||
|
||||
from pretix.base.services.cart import CartError
|
||||
from pretix.base.signals import validate_cart
|
||||
from pretix.base.views.tasks import AsyncAction
|
||||
from pretix.helpers.http import redirect_to_url
|
||||
from pretix.multidomain.urlreverse import eventreverse
|
||||
from pretix.presale.checkoutflow import get_checkout_flow
|
||||
@@ -51,7 +53,12 @@ class CheckoutView(View):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.request = request
|
||||
|
||||
if not cart_exists(request) and "async_id" not in request.GET:
|
||||
is_asyncaction_call = (
|
||||
request.method == "GET" and
|
||||
'async_id' in request.GET and
|
||||
settings.HAS_CELERY
|
||||
)
|
||||
if not cart_exists(request) and not is_asyncaction_call:
|
||||
messages.error(request, _("Your cart is empty"))
|
||||
return self.redirect(self.get_index_url(self.request))
|
||||
|
||||
@@ -78,7 +85,9 @@ class CheckoutView(View):
|
||||
utm_params = {k: v for k, v in request.GET.items() if k.startswith("utm_")}
|
||||
return self.redirect(step.get_step_url(request) + '?' + urlencode(utm_params))
|
||||
is_selected = (step.identifier == kwargs.get('step', ''))
|
||||
if "async_id" not in request.GET and not is_selected and not step.is_completed(request, warn=not is_selected):
|
||||
|
||||
is_valid_asyncaction_call = is_asyncaction_call and isinstance(step, AsyncAction)
|
||||
if not is_valid_asyncaction_call and not is_selected and not step.is_completed(request, warn=not is_selected):
|
||||
return self.redirect(step.get_step_url(request))
|
||||
if is_selected:
|
||||
if request.method.lower() in self.http_method_names:
|
||||
|
||||
@@ -5959,3 +5959,14 @@ class CustomerCheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
response = self.client.get('/%s/%s/checkout/payment/' % (self.orga.slug, self.event.slug), follow=True)
|
||||
assert 'Gift card' in response.content.decode()
|
||||
assert '(1 available)' in response.content.decode()
|
||||
|
||||
def test_validation_bypass_error_async_id_is_fixed(self):
|
||||
with scopes_disabled():
|
||||
CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=0, listed_price=0, price_after_voucher=0, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
|
||||
response = self.client.post('/%s/%s/checkout/confirm/?async_id=1' % (self.orga.slug, self.event.slug), follow=False)
|
||||
self.assertRedirects(response, '/%s/%s/checkout/customer/' % (self.orga.slug, self.event.slug),
|
||||
target_status_code=200)
|
||||
|
||||
Reference in New Issue
Block a user