<!-- Copyright (c) 2026 defconxt. All rights reserved. -->
<!-- Licensed under AGPL-3.0 — see LICENSE file for details. -->
---
name: detecting-api-data-exposure
description: >-
  Detect and prevent excessive data exposure in API responses including
  sensitive field leakage, verbose error messages, debug information
  disclosure, and improper data filtering.
domain: cybersecurity
subdomain: api-security
tags:
  - data-exposure
  - api-security
  - owasp-api3
  - sensitive-data
  - pii-leakage
version: "1.0"
author: defconxt
license: AGPL-3.0
metadata:
  mitre-attack: ["T1530", "T1213"]
  owasp-api: ["API3"]
  tools: ["curl", "burp-suite", "nuclei", "trufflehog"]
---

# Detecting API Data Exposure

## Overview

Excessive data exposure occurs when APIs return more data than the client
needs, relying on client-side filtering rather than server-side data
shaping. This leaks sensitive fields like passwords, tokens, internal IDs,
PII, and infrastructure details. OWASP API3:2023 covers broken object
property level authorization that enables data exposure.

## Prerequisites

- Tools: ["curl", "burp-suite", "nuclei", "trufflehog"]
- Valid authentication tokens for different privilege levels
- Knowledge of expected response schemas
- Authorized testing engagement with written scope

## Key Concepts

- **Over-fetching**: API returns all fields instead of only what client needs
- **PII leakage**: Exposing names, emails, SSNs, addresses in responses
- **Debug data**: Stack traces, SQL queries, internal paths in errors
- **Sensitive field exposure**: Password hashes, tokens, API keys in responses

## Workflow

### Step 1: Audit Response Payloads

```bash
# Check user profile for sensitive fields
curl -s -H "Authorization: Bearer $TOKEN" \
  https://target.com/api/users/me | jq .

# Look for sensitive field patterns
curl -s -H "Authorization: Bearer $TOKEN" \
  https://target.com/api/users/me | \
  python3 -c "
import json, sys, re
data = json.load(sys.stdin)
SENSITIVE = [
    'password', 'hash', 'salt', 'secret', 'token', 'api_key',
    'ssn', 'social_security', 'credit_card', 'cvv', 'pin',
    'private_key', 'aws_key', 'stripe_key',
    'internal_id', 'db_id', '_id', 'debug',
]
def check(obj, path=''):
    if isinstance(obj, dict):
        for k, v in obj.items():
            full_path = f'{path}.{k}' if path else k
            for s in SENSITIVE:
                if s in k.lower():
                    print(f'SENSITIVE: {full_path} = {str(v)[:50]}...')
            check(v, full_path)
    elif isinstance(obj, list) and obj:
        check(obj[0], f'{path}[0]')
check(data)
"
```

### Step 2: Test Data Filtering by Privilege Level

```bash
# Compare admin vs user response for same endpoint
echo "=== Admin Response ==="
curl -s -H "Authorization: Bearer $ADMIN_TOKEN" \
  https://target.com/api/users/123 | jq 'keys'

echo "=== User Response ==="
curl -s -H "Authorization: Bearer $USER_TOKEN" \
  https://target.com/api/users/123 | jq 'keys'

# Check list endpoints for data leakage
curl -s -H "Authorization: Bearer $USER_TOKEN" \
  https://target.com/api/users | jq '.[0] | keys'

# Test search results data exposure
curl -s -H "Authorization: Bearer $TOKEN" \
  "https://target.com/api/search?q=test" | jq '.[0] | keys'
```

### Step 3: Trigger Verbose Error Messages

```bash
# Invalid ID format to trigger stack trace
curl -s -H "Authorization: Bearer $TOKEN" \
  https://target.com/api/users/INVALID_ID | jq .

# SQL error via injection
curl -s -H "Authorization: Bearer $TOKEN" \
  "https://target.com/api/users?id='" | jq .

# Trigger server error
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"invalid": "\x00"}' \
  https://target.com/api/users | jq .

# Check error response for sensitive info patterns
curl -s -H "Authorization: Bearer $TOKEN" \
  https://target.com/api/nonexistent | \
  grep -iE '(stack|trace|debug|sql|exception|path|internal|version|framework)'
```

### Step 4: Check Public Endpoints for Data Leakage

```bash
# Test unauthenticated endpoints
PUBLIC_ENDPOINTS=(
  "/api/health"
  "/api/status"
  "/api/version"
  "/api/config"
  "/api/env"
  "/api/info"
  "/api/swagger.json"
  "/api/openapi.json"
  "/api/graphql"
  "/api/docs"
)
for EP in "${PUBLIC_ENDPOINTS[@]}"; do
  RESP=$(curl -s -o /dev/null -w "%{http_code}" "https://target.com$EP")
  [ "$RESP" != "404" ] && [ "$RESP" != "401" ] && echo "$EP: HTTP $RESP (EXPOSED)"
done

# Check for secrets in OpenAPI/Swagger spec
curl -s https://target.com/api/swagger.json | \
  grep -iE '(password|secret|key|token|example|default)' | head -20
```

### Step 5: Scan for Exposed Secrets

```bash
# Trufflehog API response scanning
curl -s -H "Authorization: Bearer $TOKEN" \
  https://target.com/api/config > /tmp/api_response.json
trufflehog filesystem /tmp/api_response.json

# Check response headers for information disclosure
curl -sI -H "Authorization: Bearer $TOKEN" \
  https://target.com/api/users/me | \
  grep -iE '(server:|x-powered-by:|x-debug:|x-request-id:)'
```

## Detection Opportunities

| Signal | Source | Description |
|--------|--------|-------------|
| PII in API responses | DLP | Sensitive data patterns in outbound traffic |
| Stack traces returned | Application logs | Error details exposed to clients |
| Config endpoint access | API gateway | Requests to /config, /env, /info |
| Large response payloads | Metrics | Responses larger than expected |

```yaml
title: API Data Exposure — Sensitive Field in Response
id: a3b4c5d6-e7f8-9012-abcd-123456789012
status: experimental
description: Detects API responses containing sensitive data patterns
logsource:
  category: application
detection:
  selection:
    response_body|re: '(?i)(password_hash|ssn|social_security|credit_card|private_key|aws_secret)'
    sc-status: 200
  condition: selection
falsepositives:
  - Admin endpoints that legitimately return user management data
level: high
tags:
  - attack.t1530
  - attack.collection
```

## Verification

- [ ] API responses contain only fields needed by the client
- [ ] Sensitive fields (passwords, tokens, PII) never in responses
- [ ] Error messages are generic — no stack traces or SQL errors
- [ ] Public endpoints do not leak internal configuration
- [ ] Response payloads differ by privilege level
- [ ] Server/version headers suppressed or genericized

## References

- [OWASP API3:2023 — Broken Object Property Level Authorization](https://owasp.org/API-Security/editions/2023/en/0xa3-broken-object-property-level-authorization/)
- [CWE-200 — Exposure of Sensitive Information](https://cwe.mitre.org/data/definitions/200.html)
- [MITRE ATT&CK T1530 — Data from Cloud Storage](https://attack.mitre.org/techniques/T1530/)
