How to fix Business Logic Errors
in ASP.NET Core
Executive Summary
Business logic errors are the silent killers of ASP.NET Core applications. Unlike SQLi or XSS, scanners won't find these. They occur when the application's design allows an attacker to manipulate the intended workflow. Most common in e-commerce and fintech, these flaws usually stem from trusting client-side input for critical state values like prices, quantities, or permission levels. If your backend trusts the 'Total' field sent from a React frontend, you're begging to be pwned.
The Vulnerable Pattern
[HttpPost("process-payment")] public async TaskCheckout([FromBody] OrderDto order) { // VULNERABILITY: Trusting the client-side calculated total. // An attacker can intercept this request and change 'Amount' to 0.01. var paymentStatus = await _paymentGateway.ChargeAsync(order.CreditCard, order.Amount); if (paymentStatus.Success) { await _orderService.FinalizeOrder(order.Id); return Ok(); } return BadRequest();
}
The Secure Implementation
The vulnerable snippet fails because it treats the incoming DTO as the source of truth for the transaction amount. An attacker using Burp Suite can simply modify the JSON payload to reduce the cost. The secure implementation ignores any price data sent by the client. Instead, it uses the OrderId to fetch the items from the database, recalculates the total based on trusted server-side records, and ensures the order belongs to the authenticated user (preventing IDOR). Rule #1: The client is in the hands of the enemy; use it only for intent, never for state.
[HttpPost("process-payment")] [Authorize] public async TaskCheckout([FromBody] PaymentRequest request) { var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value; // SECURE: Fetch the source of truth from the database var order = await _context.Orders .Include(o => o.Items) .FirstOrDefaultAsync(o => o.Id == request.OrderId && o.UserId == userId); if (order == null) return NotFound("Order not found or access denied."); // SECURE: Recalculate the total server-side. Never trust client-side math. decimal serverCalculatedTotal = order.Items.Sum(item => item.UnitPrice * item.Quantity); var paymentStatus = await _paymentGateway.ChargeAsync(request.CreditCard, serverCalculatedTotal); if (paymentStatus.Success) { order.IsPaid = true; await _context.SaveChangesAsync(); return Ok(); } return BadRequest("Payment failed.");
}
Protect your ASP.NET Core API
Don't rely on manual checks. GuardLabs detects Business Logic Errors and logic flaws in seconds.
Run Free AuditVerified by Ghost Labs Security Team
This content is continuously validated by our automated security engine and reviewed by our research team. Ghost Labs analyzes over 500+ vulnerability patterns across 40+ frameworks to provide up-to-date remediation strategies.