Safeguard
Application Security•

ASVS 5.0 V15.3.1: Return Only the Fields the Client Needs

ASVS V15.3.1 says do not serialize whole data objects. Use explicit response models so password hashes and internal flags never leave the server.

Safeguard Security Team
3 min read

ASVS 5.0 V15.3.1 requires that the application returns only the required subset of fields from a data object, rather than the whole object, because some fields should never be visible to the user. It is Level 1. The fix is to define an explicit response shape for each endpoint and map into it, instead of serializing your database model directly.

Why it matters

Returning a whole record is the easiest code to write and a common source of data exposure. The user table has a password hash, a reset token, an internal role, a billing note. The front end only displays a name and avatar, so nobody notices the rest travelling in the JSON until a researcher opens the network tab.

How to implement it

Use an allowlist. In FastAPI, a response model strips everything not declared:

from pydantic import BaseModel
from fastapi import FastAPI

app = FastAPI()

class UserPublic(BaseModel):
    id: int
    display_name: str
    avatar_url: str | None = None

@app.get("/users/{user_id}", response_model=UserPublic)
def get_user(user_id: int):
    return db.get_user(user_id)   # extra fields on the record are dropped

In Node, build the object by hand or with a mapper:

function toPublicUser(u) {
  return { id: u.id, displayName: u.displayName, avatarUrl: u.avatarUrl ?? null };
}
res.json(toPublicUser(user));

Different callers may need different shapes, such as the owner versus another user. Make those separate response models, not one model with fields blanked at runtime.

Click through it at your own pace, or open it full screen.

How to test it

  1. Call each endpoint and list every key in the response, including nested objects and arrays.
  2. Compare to the documented schema. Any extra key is a finding.
  3. Check every role. Request the same object as owner, as another user and as an anonymous caller.
  4. Write a contract test that fails when a new field appears that is not in the allowlist.
  5. Check error responses and list endpoints, which often use a different serializer.

Common mistakes

  • Hiding fields in the front end with CSS or JavaScript.
  • Using a denylist of sensitive fields, which breaks when someone adds a new column.
  • Securing the detail endpoint but not the list or search endpoint.
  • Returning ORM objects from GraphQL resolvers with a permissive type.

Quick check

Is deleting the password field before returning enough?

It fixes today's case only. An allowlist stays correct when new sensitive columns are added.

Which level does this belong to?

Level 1.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.