Pagination limits enforced
Why it matters
List endpoints without pagination caps are resource exhaustion vectors and data exfiltration shortcuts. OWASP API Security Top 10 2023 API4 (Unrestricted Resource Consumption) and CWE-400 (Uncontrolled Resource Consumption) both target this pattern. A single request for ?limit=1000000 can trigger a full table scan, exhaust database memory, and return megabytes of records in a single response. Beyond DoS, unbounded pagination is a data exfiltration technique: a single API call retrieves every user record, every order, or every payment transaction. Even authenticated users should be limited to reasonable page sizes — trust boundaries apply to consumption, not just access.
Severity rationale
Low because pagination bypass requires an authenticated request, but the impact — full table dumps and database memory exhaustion — scales with data volume.
Remediation
Clamp the limit parameter server-side — never trust the client-supplied value directly. Apply the cap in the data access layer, not just the route handler, so it can't be bypassed by callers that go around the API.
// src/lib/db/posts.ts
const MAX_PAGE_SIZE = 100
const DEFAULT_PAGE_SIZE = 20
export async function listPosts({ limit = DEFAULT_PAGE_SIZE, cursor }: PaginationArgs) {
const take = Math.min(Math.max(1, limit), MAX_PAGE_SIZE) // clamp: [1, 100]
return db.post.findMany({
take,
skip: cursor ? 1 : 0,
cursor: cursor ? { id: cursor } : undefined,
orderBy: { createdAt: 'desc' }
})
}
Return the applied limit and nextCursor in responses so clients know the actual window size.
Detection
-
ID:
pagination-limits -
Severity:
low -
What to look for: Enumerate every relevant item. Check endpoints that return lists of data (users, posts, comments). Verify that pagination is enforced with a maximum limit, preventing requests for unlimited results.
-
Pass criteria: At least 1 of the following conditions is met. List endpoints accept limit and offset/cursor parameters but cap the maximum limit (e.g., max 100 items per page). Requests for more than the max are capped or return a 400 error.
-
Fail criteria: Endpoints allow requests for unlimited results, or the limit parameter is not enforced.
-
Skip (N/A) when: The API does not return list data.
-
Detail on fail:
"GET /api/posts accepts unlimited limit parameter — requests can retrieve all posts at once"or"No pagination implemented on list endpoints" -
Remediation: Enforce pagination limits:
const MAX_LIMIT = 100 const DEFAULT_LIMIT = 20 export default async (req, res) => { let limit = parseInt(req.query.limit) || DEFAULT_LIMIT const offset = parseInt(req.query.offset) || 0 // Cap the limit if (limit > MAX_LIMIT) limit = MAX_LIMIT if (limit < 1) limit = 1 const posts = await db.post.findMany({ take: limit, skip: offset }) res.json(posts) }
External references
- cwe · CWE-400 — Uncontrolled Resource Consumption
- owasp:2023 · API4 — Unrestricted Resource Consumption
Taxons
History
- 2026-04-18·v1.0.0·Initial import from api-security·automated