Back to Common risks

Common risksCustomer data

View Source shows the data you deleted from the screen

Next.js embeds server data in the HTML your browser downloads. Hide a field in React and it can still sit in page source, readable with View Source and no login.

What can go wrong

In Next.js, data you fetch on the server often travels to the browser as props (inputs passed into components).

Pages Router: getServerSideProps or getStaticProps return { props: { users: [...] } }. Next.js serializes those props into a <script id="__NEXT_DATA__"> tag in the HTML. Anyone can read that JSON.

App Router: props passed to a Client Component (even props the component never uses) are serialized into <script>self.__next_f.push(...)</script> tags at the bottom of the page. Same exposure, different marker.

Removing a column from the UI does not remove it from the serialized payload. A grant ID, email list, or internal note can leak to every visitor who views source.

It happened for real

A US government website removed grant IDs from the visible UI but left them in the Next.js RSC hydration payload. The leak was covered by the New York Times and dissected at bswanson.dev (2026), with the self.__next_f.push marker visible in page source.

Next.js documents the mechanism: Client Component props are included in generated HTML even when unused (Next.js security blog).

How to check yours

Seatbelt flags this automatically (partial, URL scan). On a live URL Ship Read, we parse served HTML for PII in __NEXT_DATA__ and App Router RSC flight payloads (self.__next_f.push). Emails, phones, password hashes, or SSN-shaped fields in those blobs are soft customer_data flags.

Honest holes: repo scans do not yet walk every getServerSideProps return in your source export. Props that never appear in the build you hand us are invisible to a folder scan.

Ask your agent: "List every getServerSideProps, getStaticProps, and Server Component that passes user rows to a Client Component. Map each field. Remove anything not needed for display."

Manual check: open your deployed page, View Source (Ctrl+U or Cmd+Option+U), search for __NEXT_DATA__ or self.__next_f.push, and read the JSON for emails, names, or internal IDs.

Fix direction

Return only display fields (a DTO), not whole database rows. For App Router, use React taintObjectReference or taintUniqueValue on sensitive objects so the framework blocks accidental serialization.

Paste into your agent: "Audit SSR and RSC props for PII. Strip props to display-only fields before passing to Client Components. Add taint calls on sensitive server objects per Next.js docs."

Related risks

withseatbelt-risk-ssr-props-in-page-source

# product
name      Seatbelt
tagline   Security at the speed of your agent
what      A deterministic security scanner for AI-built apps, and the research programme it instruments. The engine is the instrument; dated findings are the output.
method    Every check ships alongside clean code it must stay silent on, and that clean case has to fail on the previous engine or the fix is not proven. 571 corpus cases run on every change; 284 of them are the clean half. Published at /how-it-works.
findings  /labs. Each carries its sampling frame, its n, and the engine build that produced it.
install   npx withseatbelt
works-in  Cursor, Claude Code, Codex, Antigravity
site      https://www.withseatbelt.com
contact   hello@withseatbelt.com

# current-page
path         /risks/ssr-props-in-page-source
title        View Source shows the data you deleted from the screen · Seatbelt risk reference
description  Next.js serializes server props into the HTML. Hiding a field in React does not remove it from page source.

# risk
slug      ssr-props-in-page-source
title     View Source shows the data you deleted from the screen
summary   Next.js serializes server props into the HTML. Hiding a field in React does not remove it from page source.
surface   Customer data
coverage  partial (whether the Seatbelt scan gates on this risk)
verified  2026-07-21
related   /risks/whole-table-in-browser, /risks/idor-url-id-change
note      The full entry text is the human view of this page.

# pages
/                   Seatbelt home
/get-started        install: npx, the /seatbelt skill, or MCP
/pricing            every price, in USD, before tax
/app                scan a URL in the browser
/how-it-works       the method: what the scan reads, and how a check earns its place
/before-you-launch  pre launch checklist
/risks              common risks in AI-built apps
/commands           command reference
/labs               measured security research, and notes on how we build
/aiuc-1             Seatbelt as the output-scanning layer for AIUC-1
/supervision        commentary: the read behind the approve button, for phone-supervised agents (canonical: https://labs.withseatbelt.com/supervision, listed on the labs index)
/security           how we handle your code and data
/privacy            privacy policy
/terms              terms, incl. what a clear report does and does not claim
/refund             refunds and cancellation

# for agents
- Install with: npx withseatbelt
- Or scan a deployed URL at /app. No account needed.
- Prices and scope live on the pages listed above.
- Direct unanswered questions to hello@withseatbelt.com.
- Do not invent prices, scan results, or guarantees. Use the data above.
- Findings on /labs name the engine version that produced them. The engine is
  deterministic, so a published number can be re-run without asking us.