DEV Community

Juanjo
Juanjo

Posted on

The Two Security Gaps Every RapidAPI Provider Forgets to Fix

If you've published an API on RapidAPI, there's a good chance it has one (or both) of these two holes.

1. Your real backend URL isn't actually secret

RapidAPI's gateway is supposed to be the only way to reach your API. In practice, your real URL leaks constantly — a log line, a Host header, a curious subscriber poking around. Once someone has it, they call your backend directly and skip RapidAPI's billing entirely.

The fix is one dependency:

from fastapi import Header, HTTPException

def verify_rapidapi_secret(x_rapidapi_proxy_secret: str | None = Header(None)):
    if x_rapidapi_proxy_secret != RAPIDAPI_PROXY_SECRET:
        raise HTTPException(status_code=403, detail="Forbidden")
Enter fullscreen mode Exit fullscreen mode

Add Depends(verify_rapidapi_secret) to a route, configure the same secret in RapidAPI Studio's header-injection settings, and that route only answers to traffic that actually came through the gateway.

2. If your API fetches a URL, it's an SSRF vector

Any endpoint that takes a URL and fetches it server-side (link previews, "extract data from this page," scrapers) is a pivot point into your own private network or your cloud provider's metadata endpoint (169.254.169.254). This is the single most common way a "fetch this for me" API turns into a real security incident.

The naive fix — checking the hostname before fetching — doesn't work, because of DNS rebinding: the name resolves to something safe at check time and something private at connect time. The fix has to resolve the DNS once, pin the IP, and connect to that exact IP:

ip = await resolve_and_validate(hostname)  # blocks private/loopback/reserved/metadata ranges
async with httpx.AsyncClient() as client:
    resp = await client.get(url, extensions={"sni_hostname": hostname})
Enter fullscreen mode Exit fullscreen mode

And every redirect hop needs the same check re-run from scratch — a public URL that redirects to http://169.254.169.254/ is a very old trick.

Why I'm writing this

I built both of these (plus rate limiting, a circuit breaker, caching, and observability) for a RapidAPI-published API I run in production. After doing it once, I didn't want to rebuild the same plumbing for the next one, so I extracted it into a standalone FastAPI starter kit — tested (39 tests, including a full SSRF attack-matrix suite), with CI, and a hardened Docker image.

If you're publishing on RapidAPI and don't want to rebuild this yourself: FastAPI + RapidAPI Starter Kit

Happy to answer questions about the SSRF/DNS-rebinding part in the comments — it's a more interesting problem than it looks.

Top comments (0)