No unnecessary data in responses (over-fetching)
Why it matters
Returning passwordHash, internal tokens, or entire database rows in API responses is a direct CWE-200 (exposure of sensitive information) finding and maps to OWASP A01:2021 (broken access control) when those fields reveal authorization state. A single mistakenly-included passwordHash field in a user endpoint hands an attacker every credential they need to mount offline dictionary attacks. Over-fetching also inflates response payloads and tightly couples clients to database schema, making schema changes more expensive (ISO-25010:2011 functional-suitability.functional-correctness).
Severity rationale
Low severity in aggregate because exploitation requires accessing the endpoint first, but any single sensitive-field leak (passwordHash, internalToken) is independently critical.
Remediation
Create a serializer at src/lib/serializers.ts that explicitly allowlists fields before returning database records. Never spread a database row directly into a response:
// src/lib/serializers.ts
export function serializeUser(user: User) {
const { id, name, email, createdAt, role } = user
return { id, name, email, createdAt, role }
// passwordHash, internalFlags, stripeCustomerId are never included
}
In Prisma, add explicit select clauses to queries rather than fetching and stripping fields after the fact — this prevents the data from ever crossing the DB boundary:
db.user.findUnique({ where: { id }, select: { id: true, name: true, email: true } })
Detection
- ID:
no-over-fetching - Severity:
low - What to look for: Enumerate all route handlers and for each list the fields returned in responses. Look for: (1) password hashes, internal tokens, or other sensitive fields returned alongside user data; (2) entire database rows returned when only a subset of fields is needed; (3) deeply nested related data included by default when not always needed (e.g., every user response includes their full order history). Check ORM queries for
select *-equivalent patterns, and check response serialization for field allowlisting. - Pass criteria: At least 100% of route handlers return only the fields needed for the endpoint's purpose. Sensitive fields (password, passwordHash, internalId, secret, token, hash) are explicitly excluded from responses. Response shapes are clearly scoped.
- Fail criteria: Sensitive fields (password hashes, internal tokens, internal flags) are included in API responses; or large nested relationships are always returned even when not needed; or entire database rows are returned with no field selection.
- Skip (N/A) when: The project has no database queries or all API responses are simple key/value structures with no sensitive fields. Signal: no ORM or database dependency detected, or all routes return only fields constructed manually without database row spreading.
- Detail on fail: Example:
User endpoint returns passwordHash. Identify the specific over-fetching issue (e.g., "User endpoint returns passwordHash and internalFlags fields; /api/orders includes full customer object on every item"). Max 500 chars. - Remediation: Explicitly select only the fields you need in database queries. Create a serializer in
src/lib/serializers.tsand explicitly exclude sensitive fields in responses. In Prisma: useselect: { id: true, name: true, email: true }rather than returning the whole record. In raw SQL: name columns explicitly. Create a serializer or DTO (Data Transfer Object) function that converts database records to API-safe response shapes — this is a single place to audit what you're exposing. Never return a database row directly without going through a field allowlist.
External references
- cwe · CWE-200 — Exposure of Sensitive Information to an Unauthorized Actor
- owasp:2021 · A01 — Broken Access Control
- iso-25010:2011 · functional-suitability.functional-correctness — Functional Correctness
Taxons
History
- 2026-04-18·v1.0.0·Initial import from saas-api-design·automated