Skip to content

Instantly share code, notes, and snippets.

@dexit
Forked from madebyosama/cors-anywhere.js
Created June 12, 2025 10:06
Show Gist options
  • Save dexit/00cef98dee353772e219df40e8abadea to your computer and use it in GitHub Desktop.
Save dexit/00cef98dee353772e219df40e8abadea to your computer and use it in GitHub Desktop.
CORS Anywhere with Cloudflare Workers
// Configuration
const whitelistOrigins = [".*"]; // regexp for whitelisted origins
const blacklistUrls = []; // regexp for blacklisted urls
// Helper function to check if a URI or origin is whitelisted
function isListedInWhitelist(uri, listing) {
if (!uri) return true; // Allow null origins by default
return listing.some(pattern => new RegExp(pattern).test(uri));
}
// Helper function to setup CORS headers
function setupCORSHeaders(headers, request, isPreflightRequest) {
const origin = request.headers.get("Origin");
headers.set("Access-Control-Allow-Origin", origin || "*");
if (isPreflightRequest) {
const requestMethod = request.headers.get("Access-Control-Request-Method");
const requestHeaders = request.headers.get("Access-Control-Request-Headers");
headers.set("Access-Control-Allow-Methods", requestMethod || "GET, POST, OPTIONS");
if (requestHeaders) {
headers.set("Access-Control-Allow-Headers", requestHeaders);
}
headers.set("Access-Control-Max-Age", "86400"); // 24 hours
headers.delete("X-Content-Type-Options");
}
return headers;
}
// Helper function to filter sensitive headers
function filterHeaders(headers) {
const filteredHeaders = new Headers();
for (const [key, value] of headers.entries()) {
if (!/^(origin|referer|cf-|x-forw|x-cors-headers)/i.test(key)) {
filteredHeaders.append(key, value);
}
}
return filteredHeaders;
}
addEventListener("fetch", event => {
event.respondWith(handleRequest(event));
});
async function handleRequest(event) {
const request = event.request;
const url = new URL(request.url);
const isPreflightRequest = request.method === "OPTIONS";
// Parse the target URL from the query string
const targetUrl = url.search.startsWith("?") ?
decodeURIComponent(decodeURIComponent(url.search.substr(1))) : null;
const originHeader = request.headers.get("Origin");
// Show information page if no target URL is provided
if (!url.search.startsWith("?")) {
const responseHeaders = new Headers();
setupCORSHeaders(responseHeaders, request, isPreflightRequest);
const cfData = request.cf || {};
const info = [
"CLOUDFLARE-CORS-ANYWHERE",
"",
"Usage:",
`${url.origin}/?https://api.example.com/data`,
"",
"Request Information:",
`Origin: ${originHeader || 'None'}`,
`IP: ${request.headers.get("CF-Connecting-IP") || 'Unknown'}`,
`Country: ${cfData.country || 'Unknown'}`,
`Datacenter: ${cfData.colo || 'Unknown'}`,
"",
"Rate Limits:",
"- 100,000 requests/day",
"- 1,000 requests/10 minutes"
].join("\n");
return new Response(info, {
status: 200,
headers: responseHeaders
});
}
// Check blacklist only - we're allowing all origins
if (blacklistUrls.length > 0 && isListedInWhitelist(targetUrl, blacklistUrls)) {
return new Response(
`<!DOCTYPE html>
<html>
<body>
<h1>CORS Proxy Access Denied</h1>
<p>This request is not allowed under the current security policy.</p>
<p><a href="https://github.com/Zibri/cloudflare-cors-anywhere">View Documentation</a></p>
</body>
</html>`,
{
status: 403,
headers: {
"Content-Type": "text/html",
"X-Content-Type-Options": "nosniff"
}
}
);
}
// Handle the actual proxy request
try {
// Parse and apply any custom headers
let customHeaders = {};
const corsHeaders = request.headers.get("x-cors-headers");
if (corsHeaders) {
try {
customHeaders = JSON.parse(corsHeaders);
} catch (e) {
console.error("Failed to parse x-cors-headers:", e);
}
}
// Create filtered headers for the proxied request
const filteredHeaders = filterHeaders(request.headers);
Object.entries(customHeaders).forEach(([key, value]) => {
filteredHeaders.set(key, value);
});
// Create and send the proxied request
const proxyRequest = new Request(targetUrl, {
method: isPreflightRequest ? "GET" : request.method,
headers: filteredHeaders,
body: isPreflightRequest ? null : request.body,
redirect: "follow"
});
const response = await fetch(proxyRequest);
// Prepare the response headers
const responseHeaders = new Headers(response.headers);
setupCORSHeaders(responseHeaders, request, isPreflightRequest);
// Add exposed headers
const exposedHeaders = [...response.headers.keys()];
exposedHeaders.push("cors-received-headers");
responseHeaders.set("Access-Control-Expose-Headers", exposedHeaders.join(","));
// Add received headers as JSON
const receivedHeaders = Object.fromEntries([...response.headers.entries()]);
responseHeaders.set("cors-received-headers", JSON.stringify(receivedHeaders));
// Return the final response
return new Response(
isPreflightRequest ? null : await response.arrayBuffer(),
{
status: isPreflightRequest ? 200 : response.status,
statusText: isPreflightRequest ? "OK" : response.statusText,
headers: responseHeaders
}
);
} catch (error) {
return new Response(`Proxy Error: ${error.message}`, {
status: 500,
headers: {
"Content-Type": "text/plain",
"Access-Control-Allow-Origin": originHeader || "*"
}
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment