# Batch endpoint item limits enforced

- **Pattern:** `ab-000392` (`api-security.abuse-prevention.batch-limits`)
- **Severity:** low
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-000392
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-000392)

## Why it matters

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.

## Severity rationale

Low because batch size abuse requires a crafted authenticated request, but without limits a single request can consume resources proportional to an arbitrary multiplier.

## Remediation

Validate array length before processing any batch operation. Reject oversized batches with a 400 rather than silently truncating — truncation hides the attack from monitoring.

```ts
// 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 })
}
```

## Detection

- **ID:** `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:

  ```ts
  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)
  }
  ```

## External references

- cwe CWE-400
- cwe CWE-770
- owasp API4

Taxons: cost-efficiency

HTML version: https://auditbuffet.com/patterns/ab-000392
