Docs

Issue guide · Security

Other websites can read logged-in data (CORS)

SeverityHigh
CategorySecurity
ScopeWhole site
EffortMedium
Verified bySecurity scan (weekly, or Re-scan)
Rule keysec_cors_credentials

Short answer

CORS headers tell browsers which other websites may read your responses with JavaScript. Your server sends Access-Control-Allow-Credentials: true together with * or with whatever Origin the request named. With an echoed origin, any website a logged-in visitor opens can read your pages and API responses as that visitor. Allow only a fixed list of your own domains, or drop the credentials header.

Why it matters

Normally a script on another site cannot read your pages, even though the visitor's browser holds your cookies. A server that reflects every Origin and allows credentials switches that protection off: a malicious page, ad or compromised site can quietly fetch account pages, order history, API keys or CSRF tokens from your domain while your user is logged in, and send them elsewhere. The visitor only has to open that page.

Browsers refuse to combine a literal * with credentials, so that variant is not directly exploitable, but it shows a configuration that is one edit away from the dangerous one. There is no SEO effect; this is about your users' data.

How Glimana detects it

Glimana sends one extra request to your HTTPS home page (the address it ends up on after redirects, for example the www version) with a made-up Origin: https://cors-check.glimana.invalid header. The check fails (High) when the response echoes that test origin in Access-Control-Allow-Origin together with Access-Control-Allow-Credentials: true: any website could then read logged-in responses. * combined with credentials passes, because browsers refuse that combination and nothing can be read. Only the home page is tested; API paths such as /wp-json/ or /api/ are not, so review them yourself.

How to fix it

Watch out

Do not fix this by reflecting Origin after a loose test such as "contains example.com"; https://example.com.attacker.net passes that. Match the full origin exactly, anchored at both ends, and send Vary: Origin so caches and CDNs do not serve one site's CORS answer to another.

  1. Find the finding in Glimana. Open Security; this check is in the Cookies and cross-site access group, with the evidence from the last scan under its title. The same problem is listed under Issues › Other websites can read logged-in data (CORS).
  2. Apply the fix on your platform.

    WordPress core adds no CORS headers to normal pages. Its REST API (/wp-json/) reflects the origin with credentials by design and requires a nonce for cookie-authenticated requests; that is not what this check looks at. If the home page carries these headers, the source is a plugin (CORS, headless or app-connector plugins) or a rule added to .htaccess. Search .htaccess and plugin settings for Access-Control-Allow and restrict them to your own domains.

    In config/cors.php list exact origins, for example 'allowed_origins' => ['https://app.example.com'], and limit 'paths' to the routes that need CORS, such as ['api/*']. If 'supports_credentials' => true, never combine it with 'allowed_origins' => ['*'] or a broad allowed_origins_patterns entry; the package then echoes every origin. Run php artisan config:cache afterwards.

    First remove any rule that sets Access-Control-Allow-Origin to * or to the request's origin. Apache (mod_setenvif, mod_headers):

    • SetEnvIf Origin "^(https://(www\.)?example\.com)$" CORS_ORIGIN=$1
    • Header always set Access-Control-Allow-Origin "%{CORS_ORIGIN}e" env=CORS_ORIGIN
    • Header always set Access-Control-Allow-Credentials "true" env=CORS_ORIGIN
    • Header always merge Vary "Origin"

    Nginx, in the http block: map $http_origin $cors_origin { default ""; "~^https://(www\.)?example\.com$" $http_origin; } and map $cors_origin $cors_cred { default ""; "~." "true"; }; in the server block: add_header Access-Control-Allow-Origin $cors_origin always;, add_header Access-Control-Allow-Credentials $cors_cred always;, add_header Vary Origin always;. Nginx does not send a header whose value is empty.

  3. Check it in Glimana. Press Re-scan on the Security page (up to two scans an hour) or wait for the weekly scan on Sunday; the problem closes when the check passes.

How the fix is verified

After fixing, press Re-scan on the Security page (or wait for the weekly Sunday scan); the problem closes as soon as the check passes.

Sources

Was this page helpful?

Last updated 2026-11-07 · Contact support