Fix Business Logic Errors in LoopBack
LoopBack's 'automagic' CRUD generation is a double-edged sword. Business logic errors—specifically Mass Assignment and state-machine bypasses—occur when developers trust the `@requestBody()` decorator too much. If you're blindly passing the incoming JSON object to the repository's update method, you're giving attackers the keys to override sensitive fields like 'role', 'balance', or 'isVerified'. A senior researcher looks for these 'hidden' parameters that the UI doesn't show but the API accepts.
The Vulnerable Pattern
@patch('/orders/{id}')
async updateById(
@param.path.string('id') id: string,
@requestBody() order: Order, // VULNERABLE: Accepts any field defined in the Order model
): Promise {
// Attacker can send { "totalPrice": 0.01, "status": "SHIPPED" }
await this.orderRepository.updateById(id, order);
}
The Secure Implementation
The vulnerability is Mass Assignment. The insecure code allows an attacker to manipulate the 'totalPrice' or 'status' fields because the controller doesn't filter the input. The secure implementation fixes this by: 1. Using `getModelSchemaRef` with an `exclude` list to prevent the OpenAPI UI from suggesting sensitive fields and to provide basic validation. 2. Implementing an ownership check to prevent IDOR (Insecure Direct Object Reference). 3. Explicitly whitelisting allowed properties into a new object (`updateData`) before the database operation, ensuring that even if the schema is bypassed, the logic remains intact.
@patch('/orders/{id}') async updateById( @param.path.string('id') id: string, @requestBody({ content: { 'application/json': { // Use a schema that explicitly excludes sensitive fields schema: getModelSchemaRef(Order, {partial: true, exclude: ['totalPrice', 'status', 'customerId']}), }, }, }) order: Partial, ): Promise { const existingOrder = await this.orderRepository.findById(id); if (existingOrder.customerId !== this.user.id) throw new HttpErrors.Forbidden('Not your order'); // Strict whitelisting of fields const updateData = { quantity: order.quantity, shippingAddress: order.shippingAddress };
// Business logic: Recalculate price server-side, never trust client input // updateData.totalPrice = calculatePrice(updateData.quantity);
await this.orderRepository.updateById(id, updateData); }
Your LoopBack API
might be exposed to Business Logic Errors
74% of LoopBack apps fail this check. Hackers use automated scanners to find this specific flaw. Check your codebase before they do.
Free Tier • No Credit Card • Instant Report
Verified 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.