Price Manipulation in E-commerce Applications Through Client-Side Controls and Business Logic Flaws

Critical Risk Business Logic
ecommerceprice-manipulationbusiness-logicfinancial-impactclient-side-validationcart-tamperingpayment-bypass

What it is

A critical business logic vulnerability where attackers can manipulate product prices, discounts, or total calculations in e-commerce applications by exploiting client-side price controls, insufficient server-side validation, or flawed pricing logic. This can lead to financial losses, unauthorized discounts, and purchase of items at arbitrary prices, potentially causing significant revenue impact and business disruption.

// VULNERABLE: E-commerce checkout with multiple price manipulation flaws app.post('/api/checkout', async (req, res) => { const { items, totalAmount, discountCode } = req.body; // PROBLEM: Trusting client-provided total if (totalAmount <= 0) { return res.status(400).json({ error: 'Invalid amount' }); } // PROBLEM: Not validating prices against database const order = await Order.create({ userId: req.user.id, items, total: totalAmount, // Using client total status: 'pending' }); // PROBLEM: Processing payment with unverified amount const payment = await stripe.paymentIntents.create({ amount: totalAmount * 100, currency: 'usd' }); res.json({ orderId: order.id, clientSecret: payment.client_secret }); });
// SECURE: E-commerce checkout with comprehensive price validation const { body, validationResult } = require('express-validator'); const Decimal = require('decimal.js'); app.post('/api/checkout', [ body('items').isArray().withMessage('Items must be an array'), body('items.*.productId').isUUID().withMessage('Invalid product ID'), body('items.*.quantity').isInt({ min: 1, max: 100 }).withMessage('Invalid quantity'), body('discountCode').optional().isAlphanumeric().withMessage('Invalid discount code') ], async (req, res) => { try { const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).json({ errors: errors.array() }); } const { items, discountCode } = req.body; // SECURE: Calculate total using server-side price authority let subtotal = new Decimal(0); const validatedItems = []; for (const item of items) { const priceData = await PriceAuthority.getAuthorizedPrice(item.productId); const quantity = Math.max(1, Math.floor(item.quantity)); const itemTotal = new Decimal(priceData.price).mul(quantity); validatedItems.push({ productId: item.productId, quantity, unitPrice: priceData.price, itemTotal: itemTotal.toNumber() }); subtotal = subtotal.add(itemTotal); } // SECURE: Apply discounts server-side with validation let totalDiscount = new Decimal(0); const appliedDiscounts = []; if (discountCode) { const discountManager = new SecureDiscountManager(); const discount = await discountManager.validateAndCalculateDiscount( discountCode, req.user.id, { items: validatedItems, subtotal: subtotal.toNumber() } ); if (discount) { totalDiscount = new Decimal(discount.amount); appliedDiscounts.push(discount); } } const finalTotal = subtotal.sub(totalDiscount); // Create order with validated calculations const order = await Order.create({ userId: req.user.id, items: validatedItems, subtotal: subtotal.toNumber(), discounts: appliedDiscounts, totalDiscount: totalDiscount.toNumber(), finalTotal: finalTotal.toNumber(), currency: 'USD', status: 'pending_payment', calculationHash: crypto.createHash('sha256') .update(JSON.stringify({ validatedItems, subtotal: subtotal.toNumber(), finalTotal: finalTotal.toNumber() })) .digest('hex') }); // Create payment intent with verified amount const paymentIntent = await stripe.paymentIntents.create({ amount: Math.round(finalTotal.toNumber() * 100), currency: 'usd', metadata: { orderId: order.id, calculationHash: order.calculationHash } }); res.json({ orderId: order.id, clientSecret: paymentIntent.client_secret, orderSummary: { subtotal: subtotal.toNumber(), discounts: appliedDiscounts, total: finalTotal.toNumber() } }); } catch (error) { console.error('Checkout error:', error); res.status(500).json({ error: 'Checkout failed' }); } } );

💡 Why This Fix Works

The secure implementation establishes a server-side price authority that validates all prices against the database, uses precise decimal arithmetic to prevent floating-point errors, implements comprehensive discount validation with usage tracking, and creates cryptographic hashes to verify calculation integrity during payment processing.

Why it happens

E-commerce applications that store prices, quantities, or discount information in client-side elements (HTML forms, JavaScript variables, cookies, or local storage) are vulnerable to direct manipulation by attackers who can modify these values to purchase items at arbitrary prices.

Root causes

Client-Side Price Storage and Manipulation

E-commerce applications that store prices, quantities, or discount information in client-side elements (HTML forms, JavaScript variables, cookies, or local storage) are vulnerable to direct manipulation by attackers who can modify these values to purchase items at arbitrary prices.

Preview example – HTML
<!-- VULNERABLE: Client-side price storage in HTML -->
<form id="checkout-form" action="/api/checkout" method="POST">
    <div class="product-item">
        <h3>Premium Laptop</h3>
        <p class="price">$1299.99</p>
        
        <!-- PROBLEM: Price stored in hidden form field -->
        <input type="hidden" name="product_id" value="laptop-001">
        <input type="hidden" name="price" value="1299.99">
        <input type="hidden" name="currency" value="USD">
        
        <label>Quantity:</label>
        <input type="number" name="quantity" value="1" min="1">
        
        <!-- VULNERABLE: Discount code applied client-side -->
        <input type="hidden" name="discount_applied" value="false">
        <input type="hidden" name="discount_amount" value="0">
    </div>
    
    <div class="cart-summary">
        <p>Subtotal: <span id="subtotal">$1299.99</span></p>
        <p>Tax: <span id="tax">$104.00</span></p>
        <p>Total: <span id="total">$1403.99</span></p>
        
        <!-- PROBLEM: Total calculation done client-side -->
        <input type="hidden" name="final_total" id="final_total" value="1403.99">
    </div>
    
    <button type="submit">Complete Purchase</button>
</form>

<script>
// VULNERABLE: Price calculation in JavaScript
function applyDiscount(code) {
    const discountCodes = {
        'SAVE10': 0.10,
        'EMPLOYEE50': 0.50,  // PROBLEM: High-value discount exposed
        'ADMIN99': 0.99      // PROBLEM: Admin discount accessible
    };
    
    const discount = discountCodes[code] || 0;
    const price = parseFloat(document.querySelector('input[name="price"]').value);
    const quantity = parseInt(document.querySelector('input[name="quantity"]').value);
    
    // VULNERABLE: Client-side calculation
    const subtotal = price * quantity;
    const discountAmount = subtotal * discount;
    const total = subtotal - discountAmount;
    
    // PROBLEM: Trusting client-side calculations
    document.getElementById('final_total').value = total.toFixed(2);
    document.querySelector('input[name="discount_applied"]').value = 'true';
    document.querySelector('input[name="discount_amount"]').value = discountAmount.toFixed(2);
}

// Attack scenarios:
// 1. Modify hidden price field: price="1" instead of "1299.99"
// 2. Apply admin discount codes found in JavaScript
// 3. Manipulate final_total directly: final_total="1.00"
// 4. Set negative quantities to get credits
// 5. Tamper with currency field to exploit exchange rate logic
</script>

Insufficient Server-Side Price Validation

Backend systems that accept and trust price information sent from the client without proper validation against authoritative price databases allow attackers to submit arbitrary prices during checkout processes.

Preview example – JAVASCRIPT
// VULNERABLE: Server-side checkout without price validation
const express = require('express');
const app = express();

// PROBLEM: Accepting client-provided prices
app.post('/api/checkout', async (req, res) => {
    try {
        const {
            product_id,
            price,           // DANGEROUS: Trusting client price
            quantity,
            discount_amount, // DANGEROUS: Trusting client discount
            final_total     // DANGEROUS: Trusting client calculation
        } = req.body;
        
        // INSUFFICIENT: Basic validation only
        if (!product_id || !price || !quantity) {
            return res.status(400).json({ error: 'Missing required fields' });
        }
        
        // PROBLEM: No price verification against database
        const order = {
            userId: req.user.id,
            productId: product_id,
            quantity: parseInt(quantity),
            unitPrice: parseFloat(price),        // Using client price
            discountAmount: parseFloat(discount_amount || 0),
            totalAmount: parseFloat(final_total) // Using client total
        };
        
        // VULNERABLE: Processing payment with unverified amount
        const paymentResult = await processPayment({
            amount: order.totalAmount,
            currency: 'USD',
            customerId: req.user.id
        });
        
        if (paymentResult.success) {
            // Save order with manipulated prices
            const savedOrder = await Order.create(order);
            
            res.json({
                success: true,
                orderId: savedOrder.id,
                amount: order.totalAmount
            });
        } else {
            res.status(400).json({ error: 'Payment failed' });
        }
        
    } catch (error) {
        res.status(500).json({ error: 'Checkout failed' });
    }
});

// PROBLEM: Missing price lookup function
// Should validate against authoritative price source:
/*
async function getAuthorizedPrice(productId) {
    const product = await Product.findById(productId);
    return product ? product.currentPrice : null;
}
*/

// Attack scenarios:
// 1. Submit price="0.01" for expensive items
// 2. Send negative discount_amount to increase total illegally
// 3. Submit final_total="1" regardless of actual calculation
// 4. Use expired product IDs with old lower prices

Discount and Coupon Logic Vulnerabilities

Flawed discount application logic that allows stacking unauthorized discounts, applying coupons multiple times, or exploiting edge cases in promotional calculations can be manipulated to achieve significant price reductions beyond intended limits.

Preview example – JAVASCRIPT
// VULNERABLE: Discount logic with multiple exploitable flaws
class DiscountManager {
    constructor() {
        this.appliedDiscounts = [];
    }
    
    // PROBLEM 1: No validation of discount stacking
    async applyDiscount(cartId, discountCode, userId) {
        const cart = await Cart.findById(cartId);
        const discount = await Discount.findOne({ code: discountCode });
        
        if (!discount) {
            throw new Error('Invalid discount code');
        }
        
        // PROBLEM: Not checking if discount already applied
        if (discount.isActive) {
            const discountAmount = this.calculateDiscount(cart, discount);
            
            // VULNERABLE: Allowing unlimited discount stacking
            cart.appliedDiscounts.push({
                code: discountCode,
                amount: discountAmount,
                type: discount.type
            });
            
            await cart.save();
            return discountAmount;
        }
    }
    
    // PROBLEM 2: Flawed discount calculation logic
    calculateDiscount(cart, discount) {
        let discountAmount = 0;
        
        switch (discount.type) {
            case 'percentage':
                // PROBLEM: Not capping percentage discounts
                discountAmount = cart.subtotal * (discount.value / 100);
                break;
                
            case 'fixed_amount':
                // PROBLEM: Fixed amount can exceed cart value
                discountAmount = discount.value;
                break;
                
            case 'buy_x_get_y':
                // PROBLEM: Integer overflow in calculation
                const eligibleItems = Math.floor(cart.quantity / discount.buyQuantity);
                discountAmount = eligibleItems * discount.freeItemPrice;
                break;
        }
        
        // PROBLEM: No maximum discount validation
        return discountAmount;
    }
    
    // PROBLEM 3: Race condition in discount application
    async processMultipleDiscounts(cartId, discountCodes) {
        const results = [];
        
        // VULNERABLE: Parallel processing without locking
        for (const code of discountCodes) {
            try {
                const amount = await this.applyDiscount(cartId, code, userId);
                results.push({ code, amount, success: true });
            } catch (error) {
                results.push({ code, error: error.message, success: false });
            }
        }
        
        return results;
    }
    
    // PROBLEM 4: Insufficient expiration checking
    async validateDiscountEligibility(discount, userId, cartValue) {
        // PROBLEM: Only checking basic expiration
        if (discount.expiresAt && discount.expiresAt < new Date()) {
            return false;
        }
        
        // MISSING: Usage limit per user
        // MISSING: Minimum cart value validation
        // MISSING: Product category restrictions
        // MISSING: Geographic restrictions
        
        return true;
    }
}

// VULNERABLE: API endpoint allowing discount manipulation
app.post('/api/cart/:cartId/discounts', async (req, res) => {
    const { discountCodes } = req.body;
    const { cartId } = req.params;
    
    // PROBLEM: No rate limiting on discount attempts
    // PROBLEM: Accepting multiple codes simultaneously
    const discountManager = new DiscountManager();
    
    try {
        const results = await discountManager.processMultipleDiscounts(
            cartId, 
            discountCodes
        );
        
        res.json({ results });
    } catch (error) {
        res.status(500).json({ error: 'Discount application failed' });
    }
});

// Attack scenarios:
// 1. Apply same discount code multiple times in rapid succession
// 2. Stack percentage discounts to exceed 100% (negative total)
// 3. Use expired codes during server time zone changes
// 4. Apply employee/admin discount codes found in client code
// 5. Race condition: Apply discount while cart is being modified

Payment Amount Tampering and Currency Manipulation

Vulnerabilities in payment processing where the final payment amount can be manipulated through currency conversion exploits, decimal precision attacks, or by bypassing payment amount validation during the checkout process.

Preview example – JAVASCRIPT
// VULNERABLE: Payment processing with amount manipulation
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);

class PaymentProcessor {
    // PROBLEM 1: Accepting client-provided payment amounts
    async processPayment(paymentData) {
        const {
            amount,          // DANGEROUS: Trusting client amount
            currency,        // DANGEROUS: Trusting client currency
            paymentMethodId,
            orderId
        } = paymentData;
        
        try {
            // PROBLEM: No amount verification against order
            const paymentIntent = await stripe.paymentIntents.create({
                amount: Math.round(amount * 100), // Converting to cents
                currency: currency.toLowerCase(),
                payment_method: paymentMethodId,
                confirm: true,
                metadata: {
                    orderId: orderId
                }
            });
            
            return {
                success: true,
                paymentIntentId: paymentIntent.id,
                amount: amount
            };
            
        } catch (error) {
            return {
                success: false,
                error: error.message
            };
        }
    }
    
    // PROBLEM 2: Flawed currency conversion
    async convertCurrency(amount, fromCurrency, toCurrency) {
        const exchangeRates = {
            'USD': 1.0,
            'EUR': 0.85,
            'GBP': 0.73,
            'JPY': 110.0
        };
        
        // VULNERABLE: Using static exchange rates
        const fromRate = exchangeRates[fromCurrency];
        const toRate = exchangeRates[toCurrency];
        
        if (!fromRate || !toRate) {
            throw new Error('Unsupported currency');
        }
        
        // PROBLEM: Precision loss in conversion
        return (amount / fromRate) * toRate;
    }
    
    // PROBLEM 3: Decimal precision vulnerabilities
    calculateTotal(items) {
        let total = 0;
        
        for (const item of items) {
            // VULNERABLE: Floating point arithmetic
            const itemTotal = item.price * item.quantity;
            
            // PROBLEM: Rounding errors can be exploited
            total += itemTotal;
        }
        
        // DANGEROUS: Using toFixed() for financial calculations
        return parseFloat(total.toFixed(2));
    }
    
    // PROBLEM 4: Missing payment verification
    async verifyPayment(orderId, expectedAmount) {
        const order = await Order.findById(orderId);
        
        // INSUFFICIENT: Only checking if payment exists
        const payment = await Payment.findOne({ orderId });
        
        if (payment && payment.status === 'completed') {
            // PROBLEM: Not verifying payment amount matches order
            return true;
        }
        
        return false;
    }
}

// VULNERABLE: Payment API endpoint
app.post('/api/payment/process', async (req, res) => {
    const {
        orderId,
        amount,
        currency,
        paymentMethodId
    } = req.body;
    
    const processor = new PaymentProcessor();
    
    try {
        // PROBLEM: No validation of amount against order
        const result = await processor.processPayment({
            amount: parseFloat(amount),    // Trusting client amount
            currency,                      // Trusting client currency
            paymentMethodId,
            orderId
        });
        
        if (result.success) {
            // VULNERABLE: Marking order as paid without verification
            await Order.findByIdAndUpdate(orderId, {
                status: 'paid',
                paidAmount: amount,
                paymentCurrency: currency
            });
            
            res.json({ success: true, paymentId: result.paymentIntentId });
        } else {
            res.status(400).json({ error: result.error });
        }
        
    } catch (error) {
        res.status(500).json({ error: 'Payment processing failed' });
    }
});

// Attack scenarios:
// 1. Submit amount="0.01" for high-value orders
// 2. Use currency="JPY" with USD amounts to exploit conversion
// 3. Exploit floating-point precision: 0.1 + 0.2 != 0.3
// 4. Submit payments in micro-amounts (0.001) repeatedly
// 5. Currency arbitrage using outdated exchange rates

Fixes

1

Implement Server-Side Price Authority and Validation

Establish a centralized, server-side pricing authority that validates all prices against authoritative sources and never trusts client-provided pricing information during checkout processes.

View implementation – JAVASCRIPT
// SECURE: Server-side price authority implementation
const express = require('express');
const redis = require('redis');
const { body, validationResult } = require('express-validator');

const redisClient = redis.createClient(process.env.REDIS_URL);

class PriceAuthority {
    // Centralized price lookup with caching
    static async getAuthorizedPrice(productId) {
        try {
            // Check cache first
            const cacheKey = `price:${productId}`;
            const cachedPrice = await redisClient.get(cacheKey);
            
            if (cachedPrice) {
                return JSON.parse(cachedPrice);
            }
            
            // Fetch from authoritative database
            const product = await Product.findById(productId).select('currentPrice currency isActive');
            
            if (!product || !product.isActive) {
                throw new Error('Product not found or inactive');
            }
            
            const priceData = {
                productId,
                price: product.currentPrice,
                currency: product.currency,
                timestamp: new Date().toISOString()
            };
            
            // Cache for 5 minutes
            await redisClient.setex(cacheKey, 300, JSON.stringify(priceData));
            
            return priceData;
            
        } catch (error) {
            throw new Error(`Price lookup failed: ${error.message}`);
        }
    }
    
    // Calculate order total server-side only
    static async calculateOrderTotal(items) {
        let subtotal = 0;
        const itemDetails = [];
        
        for (const item of items) {
            const priceData = await this.getAuthorizedPrice(item.productId);
            
            // Validate quantity
            const quantity = Math.max(1, Math.floor(item.quantity));
            
            // Use precise decimal arithmetic
            const itemTotal = this.preciseMultiply(priceData.price, quantity);
            
            itemDetails.push({
                productId: item.productId,
                quantity,
                unitPrice: priceData.price,
                itemTotal,
                currency: priceData.currency
            });
            
            subtotal = this.preciseAdd(subtotal, itemTotal);
        }
        
        return {
            items: itemDetails,
            subtotal,
            currency: itemDetails[0]?.currency || 'USD'
        };
    }
    
    // Precise decimal arithmetic to avoid floating point errors
    static preciseAdd(a, b) {
        return parseFloat((a + b).toFixed(2));
    }
    
    static preciseMultiply(a, b) {
        return parseFloat((a * b).toFixed(2));
    }
}

// SECURE: Checkout endpoint with proper validation
app.post('/api/checkout',
    [
        body('items').isArray().withMessage('Items must be an array'),
        body('items.*.productId').isUUID().withMessage('Invalid product ID'),
        body('items.*.quantity').isInt({ min: 1, max: 100 }).withMessage('Invalid quantity')
    ],
    async (req, res) => {
        try {
            // Validate input
            const errors = validationResult(req);
            if (!errors.isEmpty()) {
                return res.status(400).json({ errors: errors.array() });
            }
            
            const { items } = req.body;
            
            // Calculate total using server-side price authority
            const orderCalculation = await PriceAuthority.calculateOrderTotal(items);
            
            // Apply authorized discounts server-side
            const discountResult = await DiscountManager.calculateAuthorizedDiscounts(
                req.user.id,
                orderCalculation
            );
            
            const finalTotal = PriceAuthority.preciseAdd(
                orderCalculation.subtotal,
                -discountResult.totalDiscount
            );
            
            // Create order with validated prices
            const order = await Order.create({
                userId: req.user.id,
                items: orderCalculation.items,
                subtotal: orderCalculation.subtotal,
                discounts: discountResult.appliedDiscounts,
                totalDiscount: discountResult.totalDiscount,
                finalTotal,
                currency: orderCalculation.currency,
                status: 'pending_payment'
            });
            
            res.json({
                orderId: order.id,
                calculation: {
                    subtotal: orderCalculation.subtotal,
                    discounts: discountResult.appliedDiscounts,
                    total: finalTotal,
                    currency: orderCalculation.currency
                }
            });
            
        } catch (error) {
            console.error('Checkout calculation error:', error);
            res.status(500).json({ error: 'Checkout calculation failed' });
        }
    }
);
2

Implement Secure Discount Management with Proper Validation

Create a robust discount system that prevents stacking unauthorized discounts, validates discount eligibility comprehensively, and uses atomic operations to prevent race conditions.

View implementation – JAVASCRIPT
// SECURE: Comprehensive discount management system
const { v4: uuidv4 } = require('uuid');

class SecureDiscountManager {
    constructor() {
        this.discountLocks = new Map();
    }
    
    // Validate discount eligibility with comprehensive checks
    async validateDiscountEligibility(discountCode, userId, cart) {
        const discount = await Discount.findOne({ 
            code: discountCode,
            isActive: true
        });
        
        if (!discount) {
            throw new Error('Invalid or inactive discount code');
        }
        
        // Check expiration
        const now = new Date();
        if (discount.expiresAt && discount.expiresAt < now) {
            throw new Error('Discount code has expired');
        }
        
        if (discount.startsAt && discount.startsAt > now) {
            throw new Error('Discount code is not yet active');
        }
        
        // Check usage limits
        if (discount.maxUses) {
            const currentUses = await DiscountUsage.countDocuments({ discountId: discount.id });
            if (currentUses >= discount.maxUses) {
                throw new Error('Discount code usage limit exceeded');
            }
        }
        
        // Check per-user usage limits
        if (discount.maxUsesPerUser) {
            const userUses = await DiscountUsage.countDocuments({
                discountId: discount.id,
                userId
            });
            if (userUses >= discount.maxUsesPerUser) {
                throw new Error('User has exceeded usage limit for this discount');
            }
        }
        
        // Check minimum cart value
        if (discount.minimumCartValue && cart.subtotal < discount.minimumCartValue) {
            throw new Error(`Minimum cart value of ${discount.minimumCartValue} required`);
        }
        
        // Check product category restrictions
        if (discount.allowedCategories && discount.allowedCategories.length > 0) {
            const hasValidItems = cart.items.some(item => 
                discount.allowedCategories.includes(item.categoryId)
            );
            if (!hasValidItems) {
                throw new Error('No eligible items in cart for this discount');
            }
        }
        
        // Check if discount already applied
        const existingApplication = await DiscountUsage.findOne({
            discountId: discount.id,
            userId,
            orderId: cart.id,
            status: 'applied'
        });
        
        if (existingApplication) {
            throw new Error('Discount already applied to this order');
        }
        
        return discount;
    }
    
    // Calculate discount with proper limits and validation
    calculateDiscountAmount(cart, discount) {
        let discountAmount = 0;
        let applicableSubtotal = cart.subtotal;
        
        // Filter items by category if restricted
        if (discount.allowedCategories && discount.allowedCategories.length > 0) {
            applicableSubtotal = cart.items
                .filter(item => discount.allowedCategories.includes(item.categoryId))
                .reduce((sum, item) => sum + item.itemTotal, 0);
        }
        
        switch (discount.type) {
            case 'percentage':
                discountAmount = applicableSubtotal * (discount.value / 100);
                
                // Cap percentage discounts
                if (discount.maxDiscountAmount) {
                    discountAmount = Math.min(discountAmount, discount.maxDiscountAmount);
                }
                break;
                
            case 'fixed_amount':
                discountAmount = Math.min(discount.value, applicableSubtotal);
                break;
                
            case 'buy_x_get_y':
                discountAmount = this.calculateBuyXGetYDiscount(cart, discount);
                break;
                
            default:
                throw new Error('Unsupported discount type');
        }
        
        // Ensure discount doesn't exceed cart value
        return Math.min(discountAmount, cart.subtotal);
    }
    
    // Atomic discount application with locking
    async applyDiscount(cartId, discountCode, userId) {
        const lockKey = `discount_lock:${cartId}:${discountCode}`;
        const lockValue = uuidv4();
        
        try {
            // Acquire lock
            const lockAcquired = await this.acquireLock(lockKey, lockValue, 30); // 30 second timeout
            if (!lockAcquired) {
                throw new Error('Could not acquire discount lock, please try again');
            }
            
            // Start database transaction
            const session = await mongoose.startSession();
            await session.withTransaction(async () => {
                const cart = await Cart.findById(cartId).session(session);
                if (!cart) {
                    throw new Error('Cart not found');
                }
                
                // Validate discount eligibility
                const discount = await this.validateDiscountEligibility(discountCode, userId, cart);
                
                // Calculate discount amount
                const discountAmount = this.calculateDiscountAmount(cart, discount);
                
                if (discountAmount <= 0) {
                    throw new Error('Discount not applicable to current cart');
                }
                
                // Record discount usage
                await DiscountUsage.create([{
                    discountId: discount.id,
                    userId,
                    orderId: cartId,
                    discountAmount,
                    appliedAt: new Date(),
                    status: 'applied'
                }], { session });
                
                // Update cart
                await Cart.findByIdAndUpdate(cartId, {
                    $push: {
                        appliedDiscounts: {
                            code: discountCode,
                            discountId: discount.id,
                            amount: discountAmount,
                            type: discount.type
                        }
                    },
                    $inc: {
                        totalDiscount: discountAmount
                    }
                }, { session });
                
                return {
                    discountAmount,
                    discountType: discount.type,
                    discountCode
                };
            });
            
        } finally {
            // Release lock
            await this.releaseLock(lockKey, lockValue);
        }
    }
    
    // Redis-based distributed locking
    async acquireLock(key, value, timeoutSeconds) {
        const result = await redisClient.set(
            key, 
            value, 
            'PX', 
            timeoutSeconds * 1000, 
            'NX'
        );
        return result === 'OK';
    }
    
    async releaseLock(key, value) {
        const script = `
            if redis.call("get", KEYS[1]) == ARGV[1] then
                return redis.call("del", KEYS[1])
            else
                return 0
            end
        `;
        return redisClient.eval(script, 1, key, value);
    }
}
3

Implement Secure Payment Processing with Amount Verification

Create a payment processing system that verifies payment amounts against authoritative order data and uses proper decimal arithmetic to prevent precision-based attacks.

View implementation – JAVASCRIPT
// SECURE: Payment processing with comprehensive verification
const Decimal = require('decimal.js'); // Use decimal library for precise arithmetic
const crypto = require('crypto');

class SecurePaymentProcessor {
    constructor() {
        // Configure decimal precision for financial calculations
        Decimal.set({ precision: 10, rounding: Decimal.ROUND_HALF_UP });
    }
    
    // Verify payment amount against order with cryptographic integrity
    async verifyPaymentAmount(orderId, submittedAmount, submittedCurrency) {
        const order = await Order.findById(orderId).populate('items');
        
        if (!order) {
            throw new Error('Order not found');
        }
        
        if (order.status !== 'pending_payment') {
            throw new Error('Order is not in a payable state');
        }
        
        // Recalculate order total from scratch
        const calculatedTotal = await this.recalculateOrderTotal(order);
        
        // Convert currencies if necessary
        const normalizedAmount = await this.normalizeCurrency(
            submittedAmount,
            submittedCurrency,
            order.currency
        );
        
        // Use precise decimal comparison
        const submittedDecimal = new Decimal(normalizedAmount);
        const calculatedDecimal = new Decimal(calculatedTotal.finalTotal);
        
        if (!submittedDecimal.equals(calculatedDecimal)) {
            // Log potential fraud attempt
            await this.logSuspiciousActivity({
                type: 'payment_amount_mismatch',
                orderId,
                submittedAmount: submittedDecimal.toString(),
                calculatedAmount: calculatedDecimal.toString(),
                userId: order.userId,
                timestamp: new Date()
            });
            
            throw new Error('Payment amount does not match order total');
        }
        
        return calculatedTotal;
    }
    
    // Recalculate order total from authoritative sources
    async recalculateOrderTotal(order) {
        let subtotal = new Decimal(0);
        const recalculatedItems = [];
        
        // Verify each item against current prices
        for (const orderItem of order.items) {
            const currentPrice = await PriceAuthority.getAuthorizedPrice(orderItem.productId);
            
            // Use the price from when order was created (frozen prices)
            const itemTotal = new Decimal(orderItem.unitPrice).mul(orderItem.quantity);
            
            recalculatedItems.push({
                productId: orderItem.productId,
                quantity: orderItem.quantity,
                unitPrice: orderItem.unitPrice,
                itemTotal: itemTotal.toNumber()
            });
            
            subtotal = subtotal.add(itemTotal);
        }
        
        // Recalculate discounts
        let totalDiscount = new Decimal(0);
        for (const discount of order.discounts || []) {
            totalDiscount = totalDiscount.add(discount.amount);
        }
        
        // Calculate tax
        const taxRate = await this.getTaxRate(order.shippingAddress);
        const taxableAmount = subtotal.sub(totalDiscount);
        const tax = taxableAmount.mul(taxRate);
        
        const finalTotal = subtotal.sub(totalDiscount).add(tax);
        
        return {
            subtotal: subtotal.toNumber(),
            totalDiscount: totalDiscount.toNumber(),
            tax: tax.toNumber(),
            finalTotal: finalTotal.toNumber(),
            currency: order.currency
        };
    }
    
    // Secure currency conversion with real-time rates
    async normalizeCurrency(amount, fromCurrency, toCurrency) {
        if (fromCurrency === toCurrency) {
            return amount;
        }
        
        // Get real-time exchange rates from trusted source
        const exchangeRate = await this.getExchangeRate(fromCurrency, toCurrency);
        
        if (!exchangeRate) {
            throw new Error(`Currency conversion not available: ${fromCurrency} to ${toCurrency}`);
        }
        
        const amountDecimal = new Decimal(amount);
        const rateDecimal = new Decimal(exchangeRate.rate);
        
        return amountDecimal.mul(rateDecimal).toNumber();
    }
    
    // Process payment with comprehensive verification
    async processSecurePayment(paymentRequest) {
        const {
            orderId,
            paymentMethodId,
            idempotencyKey // Prevent duplicate payments
        } = paymentRequest;
        
        try {
            // Check for duplicate payment attempt
            const existingPayment = await Payment.findOne({
                orderId,
                idempotencyKey,
                status: { $in: ['completed', 'processing'] }
            });
            
            if (existingPayment) {
                throw new Error('Payment already processed');
            }
            
            // Verify order and calculate amount
            const order = await Order.findById(orderId);
            const verifiedTotal = await this.verifyPaymentAmount(
                orderId,
                order.finalTotal,
                order.currency
            );
            
            // Create payment intent with verified amount
            const paymentIntent = await stripe.paymentIntents.create({
                amount: Math.round(verifiedTotal.finalTotal * 100), // Convert to cents
                currency: order.currency.toLowerCase(),
                payment_method: paymentMethodId,
                confirmation_method: 'manual',
                confirm: true,
                metadata: {
                    orderId,
                    verifiedAmount: verifiedTotal.finalTotal.toString(),
                    calculationHash: this.generateCalculationHash(verifiedTotal)
                }
            });
            
            // Record payment with verification data
            const payment = await Payment.create({
                orderId,
                paymentIntentId: paymentIntent.id,
                amount: verifiedTotal.finalTotal,
                currency: order.currency,
                status: 'completed',
                idempotencyKey,
                verificationData: {
                    calculationHash: this.generateCalculationHash(verifiedTotal),
                    verifiedAt: new Date()
                }
            });
            
            // Update order status
            await Order.findByIdAndUpdate(orderId, {
                status: 'paid',
                paymentId: payment.id,
                paidAt: new Date()
            });
            
            return {
                success: true,
                paymentId: payment.id,
                amount: verifiedTotal.finalTotal,
                currency: order.currency
            };
            
        } catch (error) {
            // Log payment failure
            await this.logPaymentFailure({
                orderId,
                error: error.message,
                paymentMethodId,
                timestamp: new Date()
            });
            
            throw error;
        }
    }
    
    // Generate cryptographic hash of calculation for integrity verification
    generateCalculationHash(calculationData) {
        const dataString = JSON.stringify(calculationData, Object.keys(calculationData).sort());
        return crypto.createHash('sha256').update(dataString).digest('hex');
    }
}

Detect This Vulnerability in Your Code

Sourcery automatically identifies price manipulation in e-commerce applications through client-side controls and business logic flaws and many other security issues in your codebase.