CORS proxy
/kɔːrz ˈprɒksi/
A CORS proxy is a small server-side intermediary that forwards a browser's request to an upstream API and returns the response with the right Access-Control-Allow-Origin header attached. From the browser's perspective the response now comes from an origin that allows it, so the CORS check passes.
What it actually does
- Receives a request like
GET /proxy?url=https://api.example.com/data. - Issues that request server-to-server (which doesn't trigger CORS — CORS is browser-only).
- Returns the upstream response, but with
Access-Control-Allow-Origin: *(or a specific origin) added.
The browser sees a same-origin response from the proxy (allowed) instead of a cross-origin response from the upstream (potentially blocked).
When you'd use one
- Calling a third-party API that doesn't send CORS headers and you can't change.
- Development against an upstream that doesn't allowlist
localhost. - Prototypes and demos where adding a backend just to relay one request is overkill.
- Browser extensions and tools that need to fetch arbitrary URLs.
When you'd avoid one
- If you control the upstream — just configure CORS on it. That's the correct fix.
- If the data is sensitive enough that you don't want a third party to see the URLs (or the URLs are the secret, e.g. signed asset URLs).
- If you need to forward an
Authorizationheader to the upstream — most well-designed CORS proxies strip it for security reasons.
The security gotchas
A naive open CORS proxy is a textbook SSRF tool: anyone can ask it to fetch http://169.254.169.254/latest/meta-data/ and read AWS credentials, or http://10.0.0.5/ and probe internal networks. Production-grade proxies block private-IP targets, refuse non-HTTP schemes, strip dangerous headers, and rate-limit by API key. See our security writeup for the full threat model.
Example
// Direct call — blocked by CORS
fetch('https://api.example.com/data')
.then(r => r.json())
// → TypeError: blocked by CORS policy
// Through a CORS proxy — works
fetch('https://api.corsproxy.dev/proxy?url=' +
encodeURIComponent('https://api.example.com/data'), {
headers: { 'X-API-Key': 'sk_live_...' }
})
.then(r => r.json())
// → { …actual data… }