📋 What Is It?
Excessive Data Exposure is what happens when an API returns more data than the client needs and trusts the client to hide the surplus. The server serialises a whole internal object - every column of a row, every attribute of a model - and the UI displays only a handful of fields. On screen everything looks fine; in the raw JSON the hidden fields are right there for anyone with dev tools, a proxy, or curl.
The defining characteristic is that the filtering happens in the wrong place. The endpoint is authorised - the caller may call it - but the response is over-shared, leaking properties this consumer was never meant to see.
⚠️ Common Exploits
- Whole-Model Serialisation:
to_dict()/toJSON()ships every column - Secrets in Responses: password hashes, MFA seeds, reset tokens, internal keys
- Hidden-in-the-UI Fields: email, phone, DOB, exact coordinates behind a "2 mi away" label
- Internal Flags:
isAdmin, risk scores, feature toggles, billing identifiers - Over-Eager Relations: nested objects pulled in by ORM eager loading
- Verbose Errors & Debug: stack traces and full objects in error bodies
- GraphQL Over-Fetch: the schema exposes fields the resolver never filters
🔴 Attack Flow
↓
2. Compare what the UI renders with the raw JSON it received
↓
3. Spot fields the interface never shows
↓
4. Call the endpoint directly and keep everything the client discards
↓
5. IMPACT: Harvest PII and secrets at scale - from an "authorised" call!
❌ Vulnerable Code
✅ Secure Code
✓ Prevention Checklist
- Never serialise a database model straight to the response
- Define an explicit allow-list (DTO/schema) per endpoint and per audience
- Classify data - PII, secrets, internal flags - and gate each class
- Validate responses against an OpenAPI/JSON schema and strip extras
- Return the least precision that satisfies the use case
- Review generic "toJSON" helpers, ORM eager loading, and GraphQL resolvers
- Keep debug output and stack traces out of production responses
- Treat every new column as opt-in, not opt-out
- Test the raw response, not the rendered screen
🔍 Detection & Tools
Inspection:
Enforcement:
How to Test:
- Diff every rendered field against the raw JSON body
- Grep responses for
password,secret,token,ssn,lat - Call endpoints as an anonymous, a normal, and a privileged user and diff
- Query GraphQL introspection for fields the UI never requests
- Trigger errors and read what the error body contains
🌍 Real-World
These are documented incident classes - recurring patterns rather than single CVEs.
- Dating and social apps leaking coordinates: the UI shows a distance band while the API returns exact latitude and longitude, enabling trilateration to a doorstep.
- Profile endpoints returning credentials material: password hashes and MFA seeds included in a user object because the model was serialised wholesale.
- Internal flags exposed: risk scores, tiers, and
isAdminbooleans revealed in ordinary responses, mapping the app's authorization model for an attacker. - Partner integrations over-sharing: a single "user" payload reused for a third-party integration ships fields the partner should never receive.
📌 Quick Tips
- DO NOT rely on the client to hide fields
- DO NOT return model objects directly
- DO allow-list fields per endpoint and per role
- DO validate responses against a schema
- DO lower precision on sensitive values
📜 Compliance
Related Standards:
- OWASP API Security Top 10 2019 - API3
- Merged into API3:2023 Broken Object Property Level Authorization
- CWE-213 Exposure of Sensitive Information Due to Incompatible Policies
- CWE-359 Exposure of Private Personal Information
- GDPR Art. 5(1)(c) Data Minimisation