Unauthenticated Server Request Forgery via NFT Metadata
The Risk
The wallet provider's servers could be tricked into making web requests to any address an attacker pointed them at, with no login required. The attacker simply published a fake collectible whose listing told the server to go fetch a file from their own server, and the server obeyed. This is the kind of foothold attackers use to reach private internal systems that are not supposed to be visible from the internet, and to map a company's hidden infrastructure from the outside.
The Vulnerability
An unauthenticated metadata endpoint accepted a contract address and token ID, looked up the corresponding NFT metadata, then performed a server-side request to whatever URL appeared in the metadata's image or animation_url field. The result of that request, specifically the inferred media type, was reflected back to the caller as media.type.
The outbound request had no protections in place:
- No allowlist for schemes or hosts
- No filtering of private, loopback, or link-local addresses after DNS resolution
- No defense against DNS rebinding
- Redirects were followed cross-host without restriction
- No authentication required to trigger the request
The Attack
The attacker deploys a minimal NFT contract whose tokenURI() returns metadata pointing at an attacker-controlled URL.
curl -s "https://[redacted-host]/api/v1/metadata/token?contract=<ATTACKER_NFT>&id=1&type=erc721" The response echoed the attacker-controlled name, description, and media.url fields straight back, and inbound requests from the wallet provider's backend showed up at the attacker's logging endpoint.
Content-Type Oracle
By varying the response from the attacker's server, the inferred media.type reflected by the API flipped between image and video. This proved the backend was making a live server-side request and using the response, turning the endpoint into a semi-blind oracle suitable for service fingerprinting.
Redirect Following
When the attacker server returned a 302 to a different domain with a misleading content-type header, the API's reflected media.type matched the final destination, not the canary. This proved the backend follows cross-host redirects, which extends the SSRF reach beyond what an allowlist on the original URL would catch.
The Impact
- Any unauthenticated party can coerce the wallet provider's backend into outbound HTTP requests of their choice
- Internal IP ranges, cloud metadata services, and same-account services may be reachable since no IP filtering was observed
- The content-type oracle allows the attacker to distinguish reachable services from unreachable ones, enabling internal service mapping
- Redirect following expands the surface to any target the attacker can stage a redirector for
- The same code path was shared across multiple chain-specific deployments, multiplying the affected infrastructure
Remediation
- At the outbound request sink, allow only
https:and reject every other scheme. - Resolve the destination host and reject private, loopback, link-local, and cloud metadata addresses (IPv4 and IPv6) before issuing the request.
- Disable redirects, or restrict redirects to the same host that was originally validated. Re-validate the destination after every hop.
- Enforce tight timeouts, response size caps, and concurrency limits.
- The simplest fix is to remove the server-side fetch entirely and let clients fetch the media URL directly. The backend can return the URL without inspecting it.