The application leaks data it should never send - password hashes in API responses, credentials in HTML comments, internal tokens in profile endpoints, and raw stack traces on errors. One endpoint handles data correctly. Find the rest.
Sensitive data exposure (OWASP A02:2021 - Cryptographic Failures / Data Exposure) occurs when an application accidentally returns data it should protect - password hashes, session tokens, internal IDs, API keys, or credentials. It does not require an injection attack: the server volunteers the data in a normal response. Common sources are over-broad API serializers, verbose error pages, and developer comments left in templates.
| Test 1 | Card API returns password_hash, last_login_ip, and internal_user_id alongside public fields (bug) |
| Test 2 | Safe card endpoint returns only public fields - name, email, company, job_title (true negative) |
| Test 3 | HTML source of this page contains a developer comment with plaintext admin credentials (bug) |
| Test 4 | 500 error response includes a full stack trace, database password, and secret key in the body (bug) |
| Test 5 | User profile endpoint returns a live password reset token, Stripe customer ID, and 2FA backup codes (bug) |
Manual method: press
Ctrl+U (Windows/Linux) or Cmd+Option+U (Mac) to view page source,
then search for <!-- near line 2.
password_hash is a real PBKDF2 hash string,
not a placeholder - the format is algorithm$iterations$salt$hash.
id, name, email, company, job_title
and no additional keys.
Ctrl+U to view raw HTML source and search for <!--.
The comment is on line 2, outside the HTML element.
DATABASE_PASSWORD and EMAIL_HOST_PASSWORD fields.
password_reset_token JWT at jwt.io -
it contains a valid-looking user_id claim that could be used to trigger a real reset.
All tests use GET /qa-sandbox/sensitive-data/?action=<action>. No auth or body required.
For Test 3, send a plain GET /qa-sandbox/sensitive-data/ and search the HTML body for <!--.
GET /qa-sandbox/sensitive-data/?action=api-card-unsafe
# Look for these sensitive fields in the response:
# password_hash, last_login_ip, internal_user_id, account_flags
GET /qa-sandbox/sensitive-data/?action=api-card-safe # Confirm response contains ONLY: id, name, email, company, job_title
GET /qa-sandbox/sensitive-data/ Accept: text/html # In the response body search for: <!-- # Expected find: <!-- TODO: remove before prod - admin:Adm1n@2024 backup-admin:B4ckup#99 -->
GET /qa-sandbox/sensitive-data/?action=error-trace
# Response: HTTP 500
# Look for: leaked_data.settings_exposed containing
# SECRET_KEY, DATABASE_PASSWORD, EMAIL_HOST_PASSWORD
GET /qa-sandbox/sensitive-data/?action=user-profile-unsafe
# Look for: password_reset_token, stripe_customer_id,
# internal_uuid, session_token, two_factor_backup_codes