Skip to content
Vibe Coding Best Practices
Database & Backend Safety9 min read

Stop over-sharing data from API routes

How to review server routes, database queries and API responses so AI-built apps return only the data the UI actually needs.

Intermediaterg "select\(|include:|findMany|findUnique|return Response.json"rg "password|token|secret|email|role|metadata"

One of the quietest launch risks is returning too much data.

The UI needs a name, but the API returns the whole user row.

The dashboard needs a count, but the route returns every related record.

The account page needs the current user's team, but the query includes every member's email, role, metadata and internal IDs.

This happens a lot in AI-generated code because the generated query often optimises for "make the component render" rather than "send the minimum safe response."

Why over-sharing matters

Data returned to the browser is visible to the user.

Even if the UI does not display it, the network response does.

That means over-broad responses can leak:

  • internal IDs
  • user emails
  • roles and permissions
  • billing state
  • private metadata
  • feature flags
  • support notes
  • tokens
  • deleted or draft records
  • tenant data from another account

Do not rely on "we do not show it in the component."

If the browser receives it, it is exposed.

Search for broad queries

Search for patterns that commonly return too much:

rg "findMany|findUnique|include:|select\\("
rg "return Response.json|NextResponse.json|json\\("

Then ask your agent:

Review API responses and server actions for over-sharing.

For each route:
- identify what the UI actually needs
- identify what the route currently returns
- flag any private, sensitive, internal or unnecessary fields
- propose a narrower response shape
- explain whether authorization is checked before querying

The goal is to design responses, not dump database rows.

Prefer explicit select

When using an ORM, prefer explicit field selection for public responses.

Risky pattern:

Return the entire user, account, subscription or project object.

Safer pattern:

Return only id, displayName, planName and the specific flags the UI needs.

Ask:

Replace broad database includes with explicit selects.

Keep only fields used by the UI.
Do not return password hashes, tokens, internal notes, private metadata, billing provider IDs or authorization fields unless the UI has a proven need.

Check authorization before access

Narrow fields are not enough if the wrong user can request the row.

Every private route should answer:

  • who is the current user?
  • which account or tenant are they acting in?
  • are they allowed to access this record?
  • are they allowed to perform this action?

Use this prompt:

Review each API route for authorization checks.

Find any route that trusts an ID from the URL, query string, request body, cookie or client state without proving the current user owns or can access that resource.

This catches the classic bug:

/api/projects/project_123

works for anyone who guesses or obtains project_123.

Do not expose authorization internals

Sometimes the response includes fields that should exist only on the server:

  • role
  • isAdmin
  • permissions
  • stripeCustomerId
  • subscriptionProviderId
  • internalStatus
  • moderationFlags

Some of these can be safe to expose in limited contexts. But exposing them casually teaches attackers how your system works.

Ask:

Review response fields for authorization and billing internals.

Tell me which fields are safe for the browser, which should stay server-only, and which should be transformed into simpler display values.

Validate error responses

Error responses can leak too.

Avoid returning:

  • stack traces
  • raw database errors
  • provider payloads
  • SQL details
  • internal route names
  • full validation objects with sensitive input

Use this prompt:

Review API error handling.

Make sure production responses are safe for users, while logs keep enough context for debugging.
Do not expose stack traces, SQL details, secrets, tokens, provider payloads or internal implementation details to the browser.

Test with two accounts

The best verification is negative testing.

Create two accounts or tenants. Try to access data across the boundary.

Check:

  • User A cannot fetch User B's project
  • User A cannot update User B's settings
  • User A cannot list another tenant's members
  • logged-out users cannot access private data
  • normal users cannot hit admin data routes

If the route returns 404 or 403, good.

If it returns data, launch should stop.

What PageLens can help with

PageLens sees the public and authenticated app surface, not every internal query.

It can help reveal logged-in UX issues, exposed pages, trust gaps and suspicious public behaviours. Source review still needs to prove the data boundary.

Together, they answer two different questions:

  • Does the app look launch-ready from the outside?
  • Does the backend return only what users are allowed to see?

You need both before launch.

Stop over-sharing data from API routes | PageLens AI