Blog
CORS Configuration Checker for Real Website Risk
A CORS configuration checker reveals which origins can read your site responses, where credentials leak, and how to turn header findings into fast fixes.
· 6 min read

A permissive CORS header can turn a browser into an unwanted data courier. The request may look normal. Your API may authenticate correctly. But if the wrong external origin can read the response, a logged-in user's browser can hand private data to someone else's application. A CORS configuration checker exists to catch that gap before it becomes an incident, a compliance problem, or a vague ticket nobody owns.
CORS is not a scorecard item. It is a boundary decision expressed in HTTP headers. Checking it properly means testing what your site actually exposes across real endpoints, methods, origins, redirects, and credential states.
What a CORS configuration checker should test
Cross-Origin Resource Sharing tells browsers whether JavaScript running on one origin may read a response from another. An origin is the protocol, hostname, and port together. https://app.example.com and https://www.example.com are different origins. So are http://example.com and https://example.com.
A checker should begin with the response headers that establish the policy: Access-Control-Allow-Origin, Access-Control-Allow-Credentials, Access-Control-Allow-Methods, Access-Control-Allow-Headers, Access-Control-Expose-Headers, and Vary: Origin. Then it needs to test how those headers change when it sends different Origin values.
That last part separates a real inspection from a one-URL header lookup. A server may return no CORS header to an arbitrary origin but reflect any origin supplied by the request. It may permit a trusted production application on a GET request while allowing broader access on an error response, a legacy API path, or an upload endpoint. Homepage-only testing misses this. Homepage lies.
A useful CORS configuration checker also distinguishes between simple cross-origin requests and preflighted requests. When a browser intends to send methods such as PUT, PATCH, or DELETE, or nonstandard request headers, it often sends an OPTIONS preflight first. The preflight response decides whether the real request can proceed. If your production route handles GET safely but its OPTIONS handler allows arbitrary origins, methods, and headers, you have a policy gap worth examining.
The failures that deserve attention
Not every CORS finding is a vulnerability. Public resources often need broad access. A font file, public documentation endpoint, or open-status API may reasonably send Access-Control-Allow-Origin: *. The question is whether the response is intentionally public and whether browsers can access anything sensitive with it.
The highest-priority pattern is an attacker-controlled origin paired with credentials. Browsers reject the literal combination of Access-Control-Allow-Origin: * and Access-Control-Allow-Credentials: true. That built-in guard does not save you if the server reflects the requesting origin instead.
For example, this is dangerous when a response contains account data and the server accepts arbitrary origins:
httpAccess-Control-Allow-Origin: https://untrusted-example.com Access-Control-Allow-Credentials: true
With a user authenticated to your site, malicious JavaScript running at that origin may be able to make credentialed requests and read the responses. Whether exploitation is possible depends on cookie settings, authentication design, endpoint behavior, and browser rules. But this is not a finding to bury under a medium-severity badge.
Other patterns need context rather than panic. Allowing null origins can be risky because sandboxed frames, local files, and unusual browser contexts may produce Origin: null. Broadly allowing Authorization headers or sensitive custom headers across many origins expands the surface area, especially when combined with permissive methods. Returning CORS headers on redirects or errors can reveal inconsistent middleware coverage. Missing Vary: Origin can let a shared cache serve a response authorized for one origin to another when your server dynamically reflects approved origins.
Why a single test gives false confidence
Most browser-based CORS testers send one request from one origin and report the headers they see. That is helpful for debugging an integration. It is not enough for website governance.
CORS policies are commonly assembled across a stack: a CDN rule adds one header, an Nginx block adds another, application middleware makes exceptions for a partner domain, and a framework handles OPTIONS requests independently. Then a developer deploys a preview environment, adds a temporary wildcard to make a front-end build work, and forgets it exists. The visible page still works. The dashboard still says healthy. The exposure lives on an interior route.
A meaningful check should crawl the public surface first, identifying API-like routes, form handlers, CMS endpoints, static assets, feeds, search routes, and redirects. It should then probe representative endpoints using a controlled set of origins: trusted production origins, plausible subdomain lookalikes, null, arbitrary external domains, and origins that test scheme or port mismatches. It should test ordinary requests and OPTIONS where relevant.
The goal is not to fire endless hostile traffic at a site. It is to establish whether the public configuration behaves as intended. Rate limits, authentication, WAF rules, and application side effects matter. A mature checker keeps tests narrow, avoids unsafe methods, records the response chain, and makes clear what was observed versus what requires authenticated verification.
CORS configuration checker findings need a fix path
A finding without a deployment path becomes another PDF-shaped object in a backlog. The useful output answers four questions: which route returned the policy, which origin triggered it, which response headers created the exposure, and where the team should change the behavior.
For a narrow allowlist, the intended policy might look like this conceptually:
nginxif ($http_origin ~* ^https://(app|www)\.example\.com$) { add_header Access-Control-Allow-Origin $http_origin always; add_header Access-Control-Allow-Credentials true always; add_header Vary Origin always; }
That snippet is not a universal copy-paste fix. Nginx if behavior, upstream headers, caching rules, and preflight handling all require care. The point is architectural: allow known origins explicitly, emit credentials only where needed, and vary cached responses by origin when the returned policy is dynamic.
For APIs that do not need cookie-based browser access, the safer answer is often simpler: do not send Access-Control-Allow-Credentials, return a fixed allowed origin if one exists, and restrict methods and request headers to what the API actually supports. If a resource is intentionally public, a wildcard can be valid. Do not replace a clear public policy with a complicated allowlist just to make an audit look stricter.
Framework defaults deserve review too. Some CORS middleware accepts patterns that look precise but match more than expected. Others apply a global policy before route-specific authorization. Preview domains, customer subdomains, and localhost development ports are common sources of accidental overbreadth. Treat every allowed origin as a product decision, not a convenience setting.
Make CORS part of the site-wide release check
CORS changes are often introduced by infrastructure work, not application work. A CDN migration, reverse proxy change, headless CMS rollout, payment integration, or front-end deployment can alter headers without changing a line of business logic. That makes periodic checks as valuable as one-time remediation.
Build the check around meaningful site events. Scan after a hosting change, before launching a new subdomain, when exposing a new API route, and after modifying authentication cookies. Compare results between scans so teams can see whether a header was tightened, removed, or suddenly applied across more pages. A regression is easier to fix when you can point to the deployment window and exact route where it appeared.
SiteRune approaches this as crawl-based configuration analysis rather than a ceremonial homepage test. It can connect a CORS observation to the affected URL and the broader header posture, then turn the issue into implementation-ready work for the stack in front of it. Not another score. A ship file.
The practical standard is simple: public responses should be broadly readable only when you mean them to be, private responses should name the origins that need them, and every exception should survive a skeptical question from the person responsible for your next release.
Run it on a live URL
Same scan engine. Guest scans stay free.