<!-- Copyright (c) 2026 defconxt. All rights reserved. -->
<!-- Licensed under AGPL-3.0 — see LICENSE file for details. -->
---
name: detecting-api-enumeration-attacks
description: >-
  Detect and prevent API enumeration attacks that exploit predictable identifiers,
  verbose error messages, and timing differences to discover valid usernames,
  email addresses, object IDs, and API endpoints.
domain: cybersecurity
subdomain: api-security
tags:
  - enumeration
  - api-security
  - user-enumeration
  - owasp-api6
  - brute-force
version: "1.0"
author: defconxt
license: AGPL-3.0
metadata:
  mitre-attack: ["T1589", "T1087"]
  owasp-api: ["API6"]
  tools: ["curl", "ffuf", "burp-suite", "nuclei"]
---

# Detecting API Enumeration Attacks

## Overview

API enumeration attacks harvest valid identifiers by analyzing response
differences. Attackers distinguish valid from invalid usernames via status
codes, response bodies, headers, and timing. OWASP API6:2023 Unrestricted
Access to Sensitive Business Flows covers automated enumeration.

## Prerequisites

- Tools: ["curl", "ffuf", "burp-suite", "nuclei"]
- Wordlists for usernames, emails, and common identifiers
- Baseline responses for valid and invalid inputs
- Authorized testing engagement with written scope

## Key Concepts

- **User enumeration**: Distinguishing valid usernames from invalid ones
- **Response oracle**: Any observable difference that leaks validity
- **Timing oracle**: Response time differences revealing valid vs invalid
- **Resource enumeration**: Discovering valid object IDs, endpoints, tenants

## Workflow

### Step 1: Test User Enumeration via Login

```bash
# Compare responses for valid vs invalid users
curl -s -X POST -H "Content-Type: application/json" \
  -d '{"email":"known_user@target.com","password":"wrong"}' \
  https://target.com/api/login | jq '.message'

curl -s -X POST -H "Content-Type: application/json" \
  -d '{"email":"nonexistent@target.com","password":"wrong"}' \
  https://target.com/api/login | jq '.message'

# Check if error messages differ (enumeration vulnerability)
# "Invalid password" vs "User not found" = VULNERABLE
# "Invalid credentials" for both = SECURE
```

### Step 2: Timing-Based Enumeration

```bash
# Measure response times for valid vs invalid users
for EMAIL in "valid@target.com" "invalid@target.com"; do
  TIME=$(curl -s -o /dev/null -w "%{time_total}" \
    -X POST -H "Content-Type: application/json" \
    -d "{\"email\":\"$EMAIL\",\"password\":\"test\"}" \
    https://target.com/api/login)
  echo "$EMAIL: ${TIME}s"
done

# Automated timing analysis
python3 -c "
import subprocess, statistics
def measure(email, n=10):
    times = []
    for _ in range(n):
        r = subprocess.run([
            'curl', '-s', '-o', '/dev/null', '-w', '%{time_total}',
            '-X', 'POST', '-H', 'Content-Type: application/json',
            '-d', '{\"email\":\"' + email + '\",\"password\":\"x\"}',
            'https://target.com/api/login'
        ], capture_output=True, text=True, timeout=10)
        times.append(float(r.stdout))
    return statistics.mean(times), statistics.stdev(times)
valid_mean, valid_std = measure('valid@target.com')
invalid_mean, invalid_std = measure('invalid@target.com')
diff = abs(valid_mean - invalid_mean)
print(f'Valid: {valid_mean:.4f}s (±{valid_std:.4f})')
print(f'Invalid: {invalid_mean:.4f}s (±{invalid_std:.4f})')
print(f'Difference: {diff:.4f}s')
print('TIMING ORACLE DETECTED' if diff > 0.05 else 'No significant timing difference')
"
```

### Step 3: Enumerate via Registration and Password Reset

```bash
# Registration endpoint enumeration
curl -s -X POST -H "Content-Type: application/json" \
  -d '{"email":"known@target.com","password":"Test1234!"}' \
  https://target.com/api/register | jq '.message'
# "Email already registered" = enumeration vector

# Password reset enumeration
curl -s -X POST -H "Content-Type: application/json" \
  -d '{"email":"known@target.com"}' \
  https://target.com/api/password-reset | jq '.message'

curl -s -X POST -H "Content-Type: application/json" \
  -d '{"email":"nonexistent@target.com"}' \
  https://target.com/api/password-reset | jq '.message'
```

### Step 4: Automated Enumeration with ffuf

```bash
# Username enumeration via login
ffuf -u https://target.com/api/login -X POST \
  -H "Content-Type: application/json" \
  -d '{"email":"FUZZ@target.com","password":"x"}' \
  -w /usr/share/seclists/Usernames/top-usernames-shortlist.txt \
  -mc all -fr "User not found" -o enum_results.json -of json

# Endpoint enumeration
ffuf -u https://target.com/api/FUZZ \
  -w /usr/share/seclists/Discovery/Web-Content/api/api-endpoints.txt \
  -H "Authorization: Bearer $TOKEN" \
  -mc 200,301,302,403 -o endpoints.json -of json

# Tenant/organization enumeration
ffuf -u https://FUZZ.target.com/api/health \
  -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt \
  -mc 200 -o tenants.json -of json
```

## Detection Opportunities

| Signal | Source | Description |
|--------|--------|-------------|
| Sequential login attempts | Auth logs | Different usernames with same password |
| High registration rate | Application logs | Rapid account creation attempts |
| Password reset volume | Email logs | Bulk reset requests |
| 404/200 ratio patterns | API gateway | Systematic endpoint probing |

```yaml
title: API User Enumeration via Differential Responses
id: a7b8c9d0-e1f2-3456-abcd-567890123456
status: experimental
description: Detects user enumeration attempts through rapid authentication probing
logsource:
  category: application
detection:
  selection:
    event_type: authentication_failure
    endpoint|endswith:
      - '/login'
      - '/register'
      - '/password-reset'
  timeframe: 5m
  condition: selection | count(username) by source_ip > 20
falsepositives:
  - Shared NAT gateways with multiple legitimate users
level: medium
tags:
  - attack.t1589
  - attack.reconnaissance
```

## Verification

- [ ] Login returns identical responses for valid/invalid users
- [ ] Registration does not reveal existing accounts
- [ ] Password reset gives generic response regardless of email
- [ ] Response timing consistent for valid and invalid inputs
- [ ] Rate limiting enforced on enumeration-sensitive endpoints
- [ ] CAPTCHA or progressive delays on repeated failures

## References

- [OWASP API6:2023 — Unrestricted Access to Sensitive Business Flows](https://owasp.org/API-Security/editions/2023/en/0xa6-unrestricted-access-to-sensitive-business-flows/)
- [MITRE ATT&CK T1589 — Gather Victim Identity Information](https://attack.mitre.org/techniques/T1589/)
- [CWE-204 — Observable Response Discrepancy](https://cwe.mitre.org/data/definitions/204.html)
