Improper Validation of Specified Quantity in Input
Description
Improper Validation of Specified Quantity in Input occurs when a product receives input specifying a quantity (size, length, frequency, price, rate, number of operations, time, etc.) but fails to validate or incorrectly validates that the quantity has required properties. Quantities are commonly used to allocate resources, perform calculations, and control iteration. Code often depends on proper validation of these inputs for secure operation. Without proper validation, attackers can cause resource exhaustion, buffer overflows, integer overflows, or business logic violations.
Risk
Improper quantity validation has severe security implications. Buffer overflows may occur. Integer overflow attacks possible. Memory exhaustion can happen. Resource consumption attacks enabled. Business logic can be abused. Infinite loops may be triggered. Financial calculations can be manipulated. System availability can be compromised.
Solution
Implement "accept known good" validation using strict allowlists. Validate all relevant properties including length, type, acceptable ranges, and syntax. Check for business logic conformance. Avoid relying solely on malicious input detection. Validate both minimum and maximum values. Consider signed vs unsigned issues. Implement range checks before using quantities.
Common Consequences
| Impact | Details |
|---|---|
| Availability | Scope: Availability DoS - Excessive resource consumption or infinite loops. |
| Integrity | Scope: Integrity Modify Memory - Buffer overflows from invalid sizes. |
| Other | Scope: Other Business logic violations from invalid quantities. |
Example Code
Vulnerable Code
// Vulnerable: No validation of quantity inputs
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
// VULNERABLE: No validation of size parameter
void* vulnerable_allocate(size_t size) {
// VULNERABLE: No check for excessive size
// Attacker can request huge allocation
void* buffer = malloc(size); // Could exhaust memory
return buffer;
}
// VULNERABLE: No validation of count
void vulnerable_process_items(int count) {
// VULNERABLE: No upper bound check
// VULNERABLE: No negative check
for (int i = 0; i < count; i++) {
// If count is very large, runs forever
// If count is negative (when compared unsigned), unexpected behavior
process_item(i);
}
}
// VULNERABLE: Integer overflow in size calculation
void vulnerable_copy_data(const uint8_t* src, size_t element_size,
size_t element_count) {
// VULNERABLE: Multiplication can overflow
size_t total_size = element_size * element_count;
// If element_size=0x10000 and element_count=0x10000:
// total_size = 0x100000000 = 0 (32-bit overflow)
uint8_t* buffer = malloc(total_size); // Allocates 0 or small buffer
memcpy(buffer, src, total_size); // But this uses the overflowed size?
// Actually memcpy also uses total_size, but if we had:
// memcpy(buffer, src, element_size * element_count);
// The copy would overflow
}
// VULNERABLE: Negative quantity in e-commerce
struct order {
int item_id;
int quantity;
double price;
};
double vulnerable_calculate_total(struct order* orders, int num_orders) {
double total = 0;
for (int i = 0; i < num_orders; i++) {
// VULNERABLE: No validation of quantity
total += orders[i].quantity * orders[i].price;
// If quantity is negative, total decreases!
// Attacker orders -100 items and gets money back
}
return total;
}
// VULNERABLE: Array index from quantity
void vulnerable_array_access(uint8_t* data, int offset, int length) {
// VULNERABLE: No bounds checking
for (int i = 0; i < length; i++) {
// If offset or length is negative or too large, out-of-bounds access
process_byte(data[offset + i]);
}
}
// Vulnerable: Java with unvalidated quantities
public class VulnerableShoppingCart {
// VULNERABLE: No quantity validation
public double calculateTotal(List<OrderItem> items) {
double total = 0;
for (OrderItem item : items) {
// VULNERABLE: Quantity not validated
// Negative quantities credit the customer!
total += item.getQuantity() * item.getPrice();
}
return total;
}
// VULNERABLE: No validation of requested array size
public byte[] createBuffer(int requestedSize) {
// VULNERABLE: No upper limit check
// OutOfMemoryError possible
return new byte[requestedSize];
}
// VULNERABLE: Loop count from user input
public void processRequests(int count) {
// VULNERABLE: No validation of count
// Could be negative or extremely large
for (int i = 0; i < count; i++) {
processRequest(i); // DoS if count is huge
}
}
}
# Vulnerable: Python with unvalidated quantities
def vulnerable_allocate_list(size):
# VULNERABLE: No validation of size
# Can exhaust memory
return [None] * size # Creates list with 'size' elements
def vulnerable_repeat_operation(count):
# VULNERABLE: No validation of count
for i in range(count):
# If count is negative in Python 2, range() returns empty
# If count is huge, runs for very long time
do_operation(i)
def vulnerable_calculate_price(quantity, unit_price):
# VULNERABLE: No validation of quantity
# Negative quantity = negative total = refund!
return quantity * unit_price
def vulnerable_slice_data(data, offset, length):
# VULNERABLE: No bounds validation
return data[offset:offset + length]
# If offset is negative, slices from end
# If length is negative, unexpected results
Fixed Code
// Fixed: Proper validation of quantity inputs
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <limits.h>
// FIXED: Validate size parameter
void* secure_allocate(size_t size, size_t max_allowed) {
// FIXED: Check against maximum allowed
if (size == 0) {
return NULL; // Invalid request
}
if (size > max_allowed) {
log_error("Allocation size %zu exceeds maximum %zu", size, max_allowed);
return NULL;
}
void* buffer = malloc(size);
if (buffer == NULL) {
log_error("Allocation failed for size %zu", size);
}
return buffer;
}
// FIXED: Validate count with bounds
bool secure_process_items(int count, int max_count) {
// FIXED: Validate range
if (count < 0) {
log_error("Negative count: %d", count);
return false;
}
if (count > max_count) {
log_error("Count %d exceeds maximum %d", count, max_count);
return false;
}
for (int i = 0; i < count; i++) {
if (!process_item(i)) {
return false;
}
}
return true;
}
// FIXED: Detect integer overflow in size calculation
bool secure_copy_data(const uint8_t* src, size_t src_size,
size_t element_size, size_t element_count,
uint8_t** out_buffer, size_t* out_size) {
// FIXED: Check for multiplication overflow
if (element_count != 0 && element_size > SIZE_MAX / element_count) {
log_error("Size overflow: %zu * %zu", element_size, element_count);
return false;
}
size_t total_size = element_size * element_count;
// FIXED: Validate against source size
if (total_size > src_size) {
log_error("Requested size %zu exceeds source %zu", total_size, src_size);
return false;
}
uint8_t* buffer = secure_allocate(total_size, MAX_BUFFER_SIZE);
if (buffer == NULL) {
return false;
}
memcpy(buffer, src, total_size);
*out_buffer = buffer;
*out_size = total_size;
return true;
}
// FIXED: Validate quantity in e-commerce
typedef struct {
int item_id;
int quantity;
double price;
} order_item_t;
bool secure_calculate_total(const order_item_t* orders, int num_orders,
double* total_out) {
if (orders == NULL || total_out == NULL) {
return false;
}
// FIXED: Validate num_orders
if (num_orders < 0 || num_orders > MAX_ORDER_ITEMS) {
log_error("Invalid number of orders: %d", num_orders);
return false;
}
double total = 0;
for (int i = 0; i < num_orders; i++) {
// FIXED: Validate quantity is positive
if (orders[i].quantity <= 0) {
log_error("Invalid quantity %d for item %d",
orders[i].quantity, orders[i].item_id);
return false;
}
// FIXED: Validate quantity is reasonable
if (orders[i].quantity > MAX_ITEM_QUANTITY) {
log_error("Quantity %d exceeds maximum for item %d",
orders[i].quantity, orders[i].item_id);
return false;
}
// FIXED: Validate price is positive
if (orders[i].price <= 0) {
log_error("Invalid price for item %d", orders[i].item_id);
return false;
}
total += orders[i].quantity * orders[i].price;
}
*total_out = total;
return true;
}
// FIXED: Safe array access with bounds checking
bool secure_process_range(const uint8_t* data, size_t data_size,
size_t offset, size_t length) {
// FIXED: Validate offset
if (offset >= data_size) {
log_error("Offset %zu out of bounds (size=%zu)", offset, data_size);
return false;
}
// FIXED: Validate length
if (length == 0) {
return true; // Nothing to process
}
// FIXED: Check offset + length for overflow
if (length > data_size - offset) {
log_error("Length %zu exceeds remaining data at offset %zu",
length, offset);
return false;
}
for (size_t i = 0; i < length; i++) {
process_byte(data[offset + i]);
}
return true;
}
// Fixed: Java with validated quantities
public class SecureShoppingCart {
private static final int MAX_QUANTITY = 10000;
private static final int MAX_BUFFER_SIZE = 10 * 1024 * 1024; // 10 MB
private static final int MAX_ITERATIONS = 1000000;
// FIXED: Validate quantity
public double calculateTotal(List<OrderItem> items) throws ValidationException {
double total = 0;
for (OrderItem item : items) {
int quantity = item.getQuantity();
// FIXED: Validate quantity
if (quantity <= 0) {
throw new ValidationException(
"Invalid quantity: " + quantity + " for item " + item.getId());
}
if (quantity > MAX_QUANTITY) {
throw new ValidationException(
"Quantity " + quantity + " exceeds maximum " + MAX_QUANTITY);
}
double price = item.getPrice();
// FIXED: Validate price
if (price <= 0) {
throw new ValidationException(
"Invalid price for item " + item.getId());
}
total += quantity * price;
}
return total;
}
// FIXED: Validate buffer size
public byte[] createBuffer(int requestedSize) throws ValidationException {
// FIXED: Validate range
if (requestedSize <= 0) {
throw new ValidationException("Invalid buffer size: " + requestedSize);
}
if (requestedSize > MAX_BUFFER_SIZE) {
throw new ValidationException(
"Buffer size " + requestedSize + " exceeds maximum " + MAX_BUFFER_SIZE);
}
return new byte[requestedSize];
}
// FIXED: Validate loop count
public void processRequests(int count) throws ValidationException {
// FIXED: Validate count
if (count < 0) {
throw new ValidationException("Negative count: " + count);
}
if (count > MAX_ITERATIONS) {
throw new ValidationException(
"Count " + count + " exceeds maximum " + MAX_ITERATIONS);
}
for (int i = 0; i < count; i++) {
processRequest(i);
}
}
}
# Fixed: Python with validated quantities
MAX_LIST_SIZE = 10000000
MAX_ITERATIONS = 1000000
MAX_QUANTITY = 10000
def secure_allocate_list(size):
# FIXED: Validate size
if not isinstance(size, int):
raise TypeError(f"Size must be integer, got {type(size)}")
if size < 0:
raise ValueError(f"Size cannot be negative: {size}")
if size > MAX_LIST_SIZE:
raise ValueError(f"Size {size} exceeds maximum {MAX_LIST_SIZE}")
return [None] * size
def secure_repeat_operation(count):
# FIXED: Validate count
if not isinstance(count, int):
raise TypeError(f"Count must be integer, got {type(count)}")
if count < 0:
raise ValueError(f"Count cannot be negative: {count}")
if count > MAX_ITERATIONS:
raise ValueError(f"Count {count} exceeds maximum {MAX_ITERATIONS}")
for i in range(count):
do_operation(i)
def secure_calculate_price(quantity, unit_price):
# FIXED: Validate quantity
if not isinstance(quantity, (int, float)):
raise TypeError(f"Quantity must be numeric, got {type(quantity)}")
if quantity <= 0:
raise ValueError(f"Quantity must be positive: {quantity}")
if quantity > MAX_QUANTITY:
raise ValueError(f"Quantity {quantity} exceeds maximum {MAX_QUANTITY}")
# FIXED: Validate price
if not isinstance(unit_price, (int, float)):
raise TypeError(f"Price must be numeric, got {type(unit_price)}")
if unit_price <= 0:
raise ValueError(f"Price must be positive: {unit_price}")
return quantity * unit_price
def secure_slice_data(data, offset, length):
# FIXED: Validate parameters
if not isinstance(offset, int) or not isinstance(length, int):
raise TypeError("Offset and length must be integers")
if offset < 0:
raise ValueError(f"Offset cannot be negative: {offset}")
if length < 0:
raise ValueError(f"Length cannot be negative: {length}")
if offset >= len(data):
raise ValueError(f"Offset {offset} out of bounds (size={len(data)})")
if offset + length > len(data):
raise ValueError(f"Offset {offset} + length {length} exceeds data size")
return data[offset:offset + length]
CVE Examples
- CVE-2025-46687: Length check failure leading to integer overflow and heap buffer overflow.
- CVE-2019-19911: Unvalidated image band specifications causing memory exhaustion.
- CVE-2008-1440: Missing length field validation causing infinite loops.
- CVE-2008-2374: String length field validation gaps enabling memory attacks.
Related CWEs
- CWE-20: Improper Input Validation (parent)
- CWE-606: Unchecked Input for Loop Condition (child)
- CWE-789: Memory Allocation with Excessive Size Value (can precede)
- CWE-190: Integer Overflow or Wraparound (related)
References
- MITRE Corporation. "CWE-1284: Improper Validation of Specified Quantity in Input." https://cwe.mitre.org/data/definitions/1284.html
- OWASP. "Input Validation Cheat Sheet"
- CERT. "Secure Coding Standards"