How can users modify cart prices using Burp Suite, and why is this a security risk in Django?
I recently discovered a serious security issue in Django e-commerce websites where users can modify product prices before adding items to the cart.
Many developers allow users to send price data from the frontend, which can be easily tampered with using Burp Suite or browser developer tools.
Example of the Issue:
Consider a simple Django view that adds items to the cart:
def add_item(request):
product_id = request.GET.get('product_id')
price = request.GET.get('price') # User-controlled value (security risk)
qty = int(request.GET.get('qty', 1))
cart_item = {
'product_id': product_id,
'qty': qty,
'price': price, # This price comes from the user, not the database!
}
request.session['cart'] = request.session.get('cart', {})
request.session['cart'][product_id] = cart_item
request.session.modified = True
return JsonResponse({'message': 'Added to cart'})
How an Attacker Can Exploit This:
- A product costs $500 in the database.
- The user clicks "Add to Cart".
- Instead of sending the original price, the attacker intercepts the request using Burp Suite.
- The
price
field is changed to $1, and the request is forwarded. - The cart now stores the manipulated price, and the user can proceed to checkout with the wrong amount.
Why Is This a Security Risk?
- The backend trusts data from the frontend, which can be easily manipulated.
- The session stores the wrong price, leading to financial loss.
- Attackers can buy expensive products at extremely low prices by modifying request data.
Discussion Points for the Community:
- What are the best practices to prevent this?
- Should e-commerce sites always fetch prices from the database instead of accepting them from the frontend?
- What other vulnerabilities should developers be aware of when handling cart data in Django?
Would love to hear your thoughts on this!
What are the best practices to prevent this?
You don't need the price, the view should add the product_id
to the cart, and perhaps a quantity
, but adding something to the cart has no price involved. It even makes it more complicated to later apply discounts, since the price is determined per product.
Should e-commerce sites always fetch prices from the database instead of accepting them from the frontend?
Not per se, there are some APIs that determine prices on-the-fly. Bots that thus drive up the price if there is more demand, or if a competitor drops their prices.
What other vulnerabilities should developers be aware of when handling cart data in Django?
This has nothing to do with a cart, you always ask the user the absolute minimum you need to know, and by design thus limit the parameters, since this limits what you can tamper with.
I've seen some questions on StackOverflow with a similar approach. Sometimes they define a class Cart
that then operates on the session data. But this was indeed bad design, and often not only in terms of this security vulnerability, but performance, referential integrity, etc.: you add an item to a cart with a GET request, which makes no sense; and you can even add a non-existing product as well.
The GET request thus means that if a person making the request hits refresh, it is made a second time. But more importantly, GET requests should be cacheable, which clearly is not the case, and it also puts the product_id
(and price
) in the URL, which means it is at least visible in the path as well, which is not good practice either.
I always got the impression some person gave a "Django eCommerce tutorial" on Youtube, and people copied some code. But apparently some indeed moved this to production.