Skip to content

Bug: Cart Expiry Race Condition Allows Order Overselling #1359

@ArnavBallinCode

Description

@ArnavBallinCode

Cart checkout allows overselling when lock is skipped

The Problem

Found a race condition in eventyay/base/services/orders.py (lines 1180-1188) that lets multiple people buy the last ticket simultaneously.

The code has a "performance optimization" that skips locking the event during checkout when:

  • No voucher is used
  • Cart isn't expiring soon (>2 minutes left)
  • No seat selection
if positions.filter(
    Q(voucher__isnull=False) | Q(expires__lt=now() + timedelta(minutes=2)) | Q(seat__isnull=False)
).exists():
    # Performance optimization comment...
    locked = True
    lockfn = event.lock

with lockfn() as now_dt:
    # order creation

When that condition is false, lockfn stays as a no-op function and multiple checkouts can happen at once.

What Happens

Expected: If there's 1 ticket left and 2 people checkout, only 1 should succeed.

Actual: Both succeed. You get 2 orders for a quota of 1.

How to Reproduce

  1. Create an event with 1 ticket available
  2. Open two browser windows
  3. Add the product to cart in both (make sure cart expires >2 mins away, no vouchers)
  4. Click checkout in both windows at the same time
  5. Both orders go through → quota shows 2/1 sold

Works consistently in testing, confirmed on test event aer/xgzvvq on local device

Related

Found this while fixing #1344 (payment duplicate confirmation bug). Same pattern.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    In progress

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions