# Bulk Operations Verify Per-Resource Permissions

- **Pattern:** `ab-002240` (`saas-authorization.resource-auth.bulk-operations-check-each`)
- **Severity:** medium
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-002240
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-002240)

## Why it matters

Bulk operations that accept an array of IDs and apply `WHERE id IN (ids)` without scoping to the authenticated user allow cross-user interference: user A includes IDs belonging to user B in their batch and the operation succeeds. CWE-639 (Authorization Bypass Through User-Controlled Key) applies directly — the user controls the ID set. CWE-284 covers the broader access control failure. OWASP A01 flags this as a broken access control pattern. A single bulk-delete endpoint without ownership scoping can allow an authenticated attacker to delete data belonging to any other user in the system.

## Severity rationale

Medium because the attacker must be authenticated and supply valid IDs, but the ability to affect other users' data at bulk scale is a meaningful authorization failure.

## Remediation

Include the user ownership constraint in the bulk operation's WHERE clause — not as a pre-validation step, but atomically with the operation itself.

```typescript
// app/api/tasks/bulk-delete/route.ts
const { ids } = await req.json();

// Ownership filter is part of the query — not a pre-check
const result = await db.task.deleteMany({
  where: {
    id: { in: ids },
    userId: session.user.id,   // Only affects records the user owns
  },
});

// result.count < ids.length means some IDs didn't belong to the user — silently ignored
```

This pattern is safer than a pre-validation loop because it cannot be bypassed by a race condition between the check and the operation.

## Detection

- **ID:** `bulk-operations-check-each`
- **Severity:** `medium`
- **What to look for:** Count all relevant instances and enumerate each. Find API endpoints or Server Actions that accept arrays of resource IDs — bulk delete, bulk update, bulk export, multi-select operations. Check how the bulk operation is implemented: does it apply a WHERE clause that includes both the array of IDs AND the user's ID, or does it iterate over IDs without scoping to the current user?
- **Pass criteria:** Bulk database operations include the authenticated user's ID (or equivalent ownership constraint) alongside the array of requested IDs, so the operation only affects resources the user actually owns. At least 1 implementation must be verified.
- **Fail criteria:** A bulk operation accepts an array of IDs and operates on all of them using `IN (ids)` without adding the user's ownership constraint, allowing a user to affect resources owned by others by including those IDs in the array.
- **Skip (N/A) when:** No bulk operation endpoints detected — the application only supports single-resource operations.
- **Detail on fail:** `"Bulk operation at [route] does not scope operation to the authenticated user. An attacker can include arbitrary IDs in the batch."` (Note the specific endpoint.)
- **Remediation:** Include the user ownership constraint in the bulk operation's WHERE clause, not as a pre-check. This ensures atomicity — you cannot accidentally operate on resources that sneak past a pre-validation step.

  ```typescript
  // app/api/tasks/bulk-delete/route.ts
  const { ids } = await req.json();

  // This single query safely handles both authorization and deletion atomically
  const result = await db.task.deleteMany({
    where: {
      id: { in: ids },
      userId: session.user.id,   // Only deletes tasks the user actually owns
    },
  });

  // result.count tells you how many were deleted — if it's less than ids.length,
  // some IDs didn't belong to the user and were silently ignored.
  ```

- **Cross-reference:** For related patterns and deeper analysis, see the corresponding checks in other AuditBuffet audits covering this domain.

---

## External references

- cwe CWE-639
- cwe CWE-284
- owasp A01
- nist AC-3

Taxons: access-control

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