Batch endpoints that accept unbounded arrays are denial-of-service vectors dressed as productivity features. OWASP API Security Top 10 2023 API4 (Unrestricted Resource Consumption) and CWE-770 (Allocation of Resources Without Limits) both cover this class. A batch endpoint processing 10,000 items when your system is designed for 100 can exhaust connection pools, trigger N+1 database loads, and block the event loop. Unlike pagination, batch size is often not rate-limited because the request count stays low — an attacker sends one request per minute, each containing the maximum amount of work the server will perform. The same endpoint that handles 100 items correctly can be DoS-ed by requesting 100,000.
Low because batch size abuse requires a crafted authenticated request, but without limits a single request can consume resources proportional to an arbitrary multiplier.
Validate array length before processing any batch operation. Reject oversized batches with a 400 rather than silently truncating — truncation hides the attack from monitoring.
// src/app/api/batch-send/route.ts
const batchSchema = z.object({
recipients: z.array(
z.object({ email: z.string().email(), name: z.string() })
).min(1).max(100) // hard limit enforced by Zod schema
})
export async function POST(req: Request) {
const parsed = batchSchema.safeParse(await req.json())
if (!parsed.success) {
return Response.json(
{ error: 'Batch size must be 1–100 items', detail: parsed.error.flatten() },
{ status: 400 }
)
}
const results = await processBatch(parsed.data.recipients)
return Response.json({ processed: results.length })
}
ID: api-security.abuse-prevention.batch-limits
Severity: low
What to look for: Enumerate every relevant item. Check if the API has batch endpoints that accept multiple items in a single request (e.g., bulk create, bulk update). Verify that a maximum batch size is enforced.
Pass criteria: At least 1 of the following conditions is met. Batch endpoints have a maximum item count per request (e.g., max 100 items per batch). Requests exceeding the limit are rejected or truncated.
Fail criteria: Batch endpoints accept unlimited items per request, allowing resource exhaustion.
Skip (N/A) when: The API does not have batch endpoints.
Detail on fail: "POST /api/batch-create accepts arrays of unlimited length — can be used for resource exhaustion"
Remediation: Enforce batch size limits:
const MAX_BATCH_SIZE = 100
export default async (req, res) => {
const items = req.body.items
if (!Array.isArray(items) || items.length > MAX_BATCH_SIZE) {
return res.status(400).json({
error: `Batch size must be between 1 and ${MAX_BATCH_SIZE}`
})
}
const results = await Promise.all(
items.map(item => db.create(item))
)
res.json(results)
}