CORS Auditor avatar

CORS Auditor

Pricing

Pay per usage

Go to Apify Store
CORS Auditor

CORS Auditor

Audit a public URL's CORS configuration in one API call. Inspects Access-Control headers on simple and preflight requests, detects wildcard-with-credentials, reflected origins missing Vary: Origin, null-echo origins, and over-permissive methods or headers. Returns score, grade, and recommendations.

Pricing

Pay per usage

Rating

0.0

(0)

Developer

Sanskar Jaiswal

Sanskar Jaiswal

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

7 days ago

Last modified

Share

Audit a public URL's Cross-Origin Resource Sharing (CORS) configuration in one API call. Inspects Access-Control-Allow-Origin, Access-Control-Allow-Credentials, Access-Control-Allow-Methods, Access-Control-Allow-Headers, Access-Control-Expose-Headers, Access-Control-Max-Age, and Vary: Origin on both a simple (GET-with-Origin) request and an OPTIONS preflight. Detects wildcard origins combined with credentials, reflected-echo servers missing Vary: Origin, null origin echo, and over-permissive method or header exposure. Returns a per-header analysis, score, letter grade, and security/devops recommendations. Built for API teams, security teams, devops engineers, and site migration QA.

Use cases

  • API teams - verify CORS preflight returns the right Access-Control-Allow-Methods, Allow-Headers, and a sensible Max-Age before shipping a new endpoint or version
  • Security teams - catch over-permissive CORS configurations (Access-Control-Allow-Origin: * with credentials, null origin echo, reflected origins without Vary: Origin) that leak authenticated responses to attacker-controlled origins
  • Devops teams - confirm preflight and simple-response CORS headers survive moves between framework versions, reverse proxies, API gateways, and edge providers
  • Site migration QA - detect regressions where a new CDN, load balancer, or rewrite rule strips Access-Control-* headers or stops echoing Vary: Origin
  • Frontend platform teams - debug cross-origin fetch failures and credential-not-included errors against API hosts

Input

FieldTypeRequiredDefaultDescription
startUrlstringyes-Public URL to audit. The actor fetches the resource with an Origin header and performs an OPTIONS preflight. HTTP and HTTPS only. Private IP ranges are blocked.
probeOriginstringnohttps://probe.cors-auditor.localCross-origin to send in the Origin header. Used to detect reflected-echo servers. Accepts https://host[:port] or a bare hostname.
probeMethodstringnoPOSTHTTP method requested via Access-Control-Request-Method during preflight. Use the method your API actually needs (e.g., POST, PUT, PATCH, DELETE).
timeoutSecondsintegerno10Per-request timeout (3-30 seconds)

Example input

{
"startUrl": "https://api.example.com/v1/health",
"probeOrigin": "https://app.example.com",
"probeMethod": "POST",
"timeoutSeconds": 10
}

Output

A single dataset item with the full audit:

FieldTypeDescription
inputUrlstringThe URL provided as input
finalUrlstringFinal URL after redirects on the simple request
httpsbooleanWhether the final response was served over HTTPS
statusintegerHTTP status code of the simple (GET) request
preflightStatusinteger | nullHTTP status code of the OPTIONS preflight response, or null if no usable response was returned
allowOriginstring | nullAccess-Control-Allow-Origin value on the simple GET response
allowOriginPreflightstring | nullAccess-Control-Allow-Origin value on the OPTIONS preflight response
allowsCredentialsbooleanWhether Access-Control-Allow-Credentials: true is present on either response
isWildcardbooleanWhether Access-Control-Allow-Origin is the wildcard * on either response
isReflectedbooleanWhether the server reflected the probe Origin back instead of using a static value
isNullEchobooleanWhether Access-Control-Allow-Origin is the literal string null (often exploitable from sandboxed iframes and file: origins)
allowMethodsarrayAccess-Control-Allow-Methods values from the preflight response
allowHeadersarrayAccess-Control-Allow-Headers values from the preflight response
exposeHeadersarrayAccess-Control-Expose-Headers values from the simple response
maxAgeinteger | nullAccess-Control-Max-Age from the preflight response (seconds)
varyOriginbooleanWhether Vary includes Origin on either response (required when Allow-Origin is reflected)
headersarrayPer-header analysis (see below)
issuesarrayAggregated issue descriptions
scoreintegerCORS readiness score (0-100)
gradestringLetter grade (A+, A, B, C, D, E, F)
checkedAtstringISO 8601 timestamp
recommendationsarrayActionable recommendations

headers array

Each entry contains:

FieldTypeDescription
namestringDisplay name of the header check
headerstringCanonical check key
statusstringgood, warn, missing, or info
notestringHuman-readable explanation of the current state
weightintegerWeight of this check in the score
recommendationstring | nullFix recommendation, or null when the check is good

Headers checked

CheckHeader(s)What is checked
Allow-Origin (simple)Access-Control-Allow-Origin on GETpresence, wildcard, null echo, reflected-echo behavior, static-literal origins
Allow-Origin (preflight)Access-Control-Allow-Origin on OPTIONSpresence, wildcard, null echo, reflected-echo behavior, static-literal origins
Allow-CredentialsAccess-Control-Allow-Credentialspresence; flagged as a warning when paired with Allow-Origin: * (browsers reject the combination)
Allow-MethodsAccess-Control-Allow-Methodspresence on preflight; warns when the requested method is not in the list and when * is used (non-standard)
Allow-HeadersAccess-Control-Allow-Headerspresence on preflight; warns when * is used (non-standard for client headers)
Expose-HeadersAccess-Control-Expose-Headerspresence on simple response; warns when * is used (non-standard)
Max-AgeAccess-Control-Max-Agepresence; warns when shorter than 600 seconds (browsers preflight every request)
Vary: OriginVaryrequired when Allow-Origin is reflected from the request; warns when missing (CDN caches may pin one client's origin)

Security-relevant detections

The audit reports the following CORS risks:

  • Wildcard with credentials - Access-Control-Allow-Origin: * combined with Access-Control-Allow-Credentials: true is invalid per the Fetch spec; browsers ignore it and credentials fall back to same-origin.
  • Null origin echo - Access-Control-Allow-Origin: null is treated as a permissive origin by browsers, attacker-controlled from sandboxed iframes, data: URLs, and file: origins.
  • Reflected origin without Vary: Origin - servers that echo the request Origin back must include Vary: Origin; otherwise a CDN may serve one client's Allow-Origin to a different client and bypass the intended origin allow-list.
  • Over-permissive method/header wildcard - Access-Control-Allow-Methods: * and Access-Control-Allow-Headers: * are non-standard; many browsers ignore the wildcard for client-initiated header lists.
  • Unlisted preflight method - when probeMethod requests a method that is not in Access-Control-Allow-Methods, the preflight will be rejected by the browser.

Grading scale

Score rangeGrade
95-100A+
85-94A
75-84B
65-74C
50-64D
30-49E
0-29F

Example output

{
"inputUrl": "https://api.example.com/v1/health",
"finalUrl": "https://api.example.com/v1/health",
"https": true,
"status": 200,
"preflightStatus": 204,
"allowOrigin": "https://app.example.com",
"allowOriginPreflight": "https://app.example.com",
"allowsCredentials": true,
"isWildcard": false,
"isReflected": false,
"isNullEcho": false,
"allowMethods": ["get", "post", "put", "delete"],
"allowHeaders": ["authorization", "content-type"],
"exposeHeaders": ["x-trace-id"],
"maxAge": 86400,
"varyOrigin": true,
"headers": [
{
"name": "Access-Control-Allow-Origin (simple)",
"header": "allow-origin-simple",
"status": "good",
"note": "Access-Control-Allow-Origin: https://app.example.com (static origin) on the simple response.",
"weight": 25,
"recommendation": null
},
{
"name": "Access-Control-Allow-Origin (preflight)",
"header": "allow-origin-preflight",
"status": "good",
"note": "Access-Control-Allow-Origin: https://app.example.com (static origin) on the preflight response.",
"weight": 20,
"recommendation": null
}
],
"issues": [],
"score": 95,
"grade": "A+",
"checkedAt": "2026-08-10T12:00:00.000Z",
"recommendations": [
"CORS configuration looks consistent and well-scoped. Re-run after API deploys or origin changes to catch regressions."
]
}

Security

  • Only public HTTP/HTTPS URLs are accepted
  • SSRF protection: localhost, private IPv4/IPv6, and DNS-resolving-to-private IPs are blocked
  • URLs with embedded credentials are rejected
  • Redirects are manually revalidated before following (max 3)
  • No browser automation, no cookies stored, no body retained beyond draining
  • probeOrigin is validated and stripped to its scheme/host/port; it is used only as the Origin request header, never as a target

Pricing

Pay per event:

EventPrice
Actor start$0.005
URL audited$0.01

A single URL audit (one simple GET plus one OPTIONS preflight) costs approximately $0.015.

FAQ

How is this different from the HTTP Security Headers Auditor? The HTTP Security Headers Auditor checks security response headers such as Strict-Transport-Security, Content-Security-Policy, X-Frame-Options, X-Content-Type-Options, and Referrer-Policy. This actor focuses exclusively on Cross-Origin Resource Sharing headers (Access-Control-Allow-Origin, Access-Control-Allow-Credentials, Access-Control-Allow-Methods, Access-Control-Allow-Headers, Access-Control-Expose-Headers, Access-Control-Max-Age) and Vary: Origin, evaluated against both a simple GET and an OPTIONS preflight.

Why does the actor perform two requests? Browsers enforce CORS differently for simple requests (GET, some POST forms) and preflighted requests (anything with custom headers or non-simple methods). A simple GET with Origin reveals the runtime CORS posture; an OPTIONS preflight with Access-Control-Request-Method reveals the policy the server advertises to browsers. Comparing both catches common misconfigurations where the API answers preflight correctly but returns a different Allow-Origin on the actual response.

How should I set probeMethod? Use the HTTP method your frontend actually calls the API with. The actor sends it via Access-Control-Request-Method on the preflight and verifies Access-Control-Allow-Methods includes it. POST covers most JSON APIs; use PATCH, PUT, or DELETE for REST endpoints that mutate state.

Why is Access-Control-Allow-Origin: null flagged? Some servers return null when an unrecognized Origin is sent (for example, behind a proxy that strips unknown origins). Browsers treat null as a specific origin that sandboxed iframes, data: URLs, and file: pages can produce, which means attacker-controlled pages may be able to read authenticated responses. Return a concrete trusted origin or omit Allow-Origin for disallowed origins.

What is reflected-echo and why does it need Vary: Origin? Many servers validate the request Origin against an allow-list and, when allowed, return Access-Control-Allow-Origin: <request origin> (an "echo"). When Vary: Origin is omitted, a shared CDN cache may store the response with one client's Allow-Origin value and serve it to a different client whose Origin is not on the allow-list. The audit flags this configuration as a warning.

Does the actor follow redirects? Yes, up to 3 redirects. Each redirect target is revalidated for SSRF safety before it is followed. CORS headers are evaluated on the final response.

Can I audit static assets (CSS, JS, fonts)? Yes. The behavior is identical. Static assets intended for cross-origin use should return Access-Control-Allow-Origin: * (without credentials); assets that must be authenticated should return a specific origin plus Vary: Origin.