CORS Auditor
Pricing
Pay per usage
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
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
7 days ago
Last modified
Categories
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 sensibleMax-Agebefore shipping a new endpoint or version - Security teams - catch over-permissive CORS configurations (
Access-Control-Allow-Origin: *with credentials,nullorigin echo, reflected origins withoutVary: 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 echoingVary: Origin - Frontend platform teams - debug cross-origin fetch failures and credential-not-included errors against API hosts
Input
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
startUrl | string | yes | - | 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. |
probeOrigin | string | no | https://probe.cors-auditor.local | Cross-origin to send in the Origin header. Used to detect reflected-echo servers. Accepts https://host[:port] or a bare hostname. |
probeMethod | string | no | POST | HTTP method requested via Access-Control-Request-Method during preflight. Use the method your API actually needs (e.g., POST, PUT, PATCH, DELETE). |
timeoutSeconds | integer | no | 10 | Per-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:
| Field | Type | Description |
|---|---|---|
inputUrl | string | The URL provided as input |
finalUrl | string | Final URL after redirects on the simple request |
https | boolean | Whether the final response was served over HTTPS |
status | integer | HTTP status code of the simple (GET) request |
preflightStatus | integer | null | HTTP status code of the OPTIONS preflight response, or null if no usable response was returned |
allowOrigin | string | null | Access-Control-Allow-Origin value on the simple GET response |
allowOriginPreflight | string | null | Access-Control-Allow-Origin value on the OPTIONS preflight response |
allowsCredentials | boolean | Whether Access-Control-Allow-Credentials: true is present on either response |
isWildcard | boolean | Whether Access-Control-Allow-Origin is the wildcard * on either response |
isReflected | boolean | Whether the server reflected the probe Origin back instead of using a static value |
isNullEcho | boolean | Whether Access-Control-Allow-Origin is the literal string null (often exploitable from sandboxed iframes and file: origins) |
allowMethods | array | Access-Control-Allow-Methods values from the preflight response |
allowHeaders | array | Access-Control-Allow-Headers values from the preflight response |
exposeHeaders | array | Access-Control-Expose-Headers values from the simple response |
maxAge | integer | null | Access-Control-Max-Age from the preflight response (seconds) |
varyOrigin | boolean | Whether Vary includes Origin on either response (required when Allow-Origin is reflected) |
headers | array | Per-header analysis (see below) |
issues | array | Aggregated issue descriptions |
score | integer | CORS readiness score (0-100) |
grade | string | Letter grade (A+, A, B, C, D, E, F) |
checkedAt | string | ISO 8601 timestamp |
recommendations | array | Actionable recommendations |
headers array
Each entry contains:
| Field | Type | Description |
|---|---|---|
name | string | Display name of the header check |
header | string | Canonical check key |
status | string | good, warn, missing, or info |
note | string | Human-readable explanation of the current state |
weight | integer | Weight of this check in the score |
recommendation | string | null | Fix recommendation, or null when the check is good |
Headers checked
| Check | Header(s) | What is checked |
|---|---|---|
| Allow-Origin (simple) | Access-Control-Allow-Origin on GET | presence, wildcard, null echo, reflected-echo behavior, static-literal origins |
| Allow-Origin (preflight) | Access-Control-Allow-Origin on OPTIONS | presence, wildcard, null echo, reflected-echo behavior, static-literal origins |
| Allow-Credentials | Access-Control-Allow-Credentials | presence; flagged as a warning when paired with Allow-Origin: * (browsers reject the combination) |
| Allow-Methods | Access-Control-Allow-Methods | presence on preflight; warns when the requested method is not in the list and when * is used (non-standard) |
| Allow-Headers | Access-Control-Allow-Headers | presence on preflight; warns when * is used (non-standard for client headers) |
| Expose-Headers | Access-Control-Expose-Headers | presence on simple response; warns when * is used (non-standard) |
| Max-Age | Access-Control-Max-Age | presence; warns when shorter than 600 seconds (browsers preflight every request) |
| Vary: Origin | Vary | required 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 withAccess-Control-Allow-Credentials: trueis invalid per the Fetch spec; browsers ignore it and credentials fall back to same-origin. - Null origin echo -
Access-Control-Allow-Origin: nullis treated as a permissive origin by browsers, attacker-controlled from sandboxed iframes,data:URLs, andfile:origins. - Reflected origin without
Vary: Origin- servers that echo the requestOriginback must includeVary: Origin; otherwise a CDN may serve one client'sAllow-Originto a different client and bypass the intended origin allow-list. - Over-permissive method/header wildcard -
Access-Control-Allow-Methods: *andAccess-Control-Allow-Headers: *are non-standard; many browsers ignore the wildcard for client-initiated header lists. - Unlisted preflight method - when
probeMethodrequests a method that is not inAccess-Control-Allow-Methods, the preflight will be rejected by the browser.
Grading scale
| Score range | Grade |
|---|---|
| 95-100 | A+ |
| 85-94 | A |
| 75-84 | B |
| 65-74 | C |
| 50-64 | D |
| 30-49 | E |
| 0-29 | F |
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
probeOriginis validated and stripped to its scheme/host/port; it is used only as theOriginrequest header, never as a target
Pricing
Pay per event:
| Event | Price |
|---|---|
| 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.