highSeverity: highRisk ratingHow usable this gap is to an attacker. Severity sets the posture penalty: critical βˆ’40, high βˆ’20, medium βˆ’10, low βˆ’4, info βˆ’1. Higher severity means fix it sooner.App server (CORS)Where it livesImplementationThis fix is applied in: App server (CORS). That's the surface you'll edit, DNS, response headers, or a static file.~15 minTime to fixEffortRoughly 15 minutes of hands-on work, propagation aside. Most of these are copy-paste.+20 posture+20 postureScore impactPoints this fix recovers in the ApeCyber posture score (0–100). Posture = 100 minus the severity penalty of every open finding; clearing this finding adds these points back.

CORS: never pair a wildcard with credentials

Bind credentials to a named origin instead of a wildcard so no other site can make authenticated reads

The threat

Two things showed up together on your API: Access-Control-Allow-Origin: * and Access-Control-Allow-Credentials: true. On their own, each is ordinary. Together they try to tell the browser β€œany website may send this user’s cookies to my API and read what comes back,” which is the Same-Origin Policy, the rule that normally stops one site from reading another, switched off for your API.

In practice browsers refuse the literal * when credentials are involved, so code that wants this behavior usually reflects the caller’s origin instead and ends up in the same place: any site a logged-in visitor opens can quietly make authenticated calls to your API and read their data back. That is a direct data-theft path, which is why this rates higher than a plain reflected origin.

The exact fix

Two moves, and you almost always want the first.

1. Decide whether you need credentials cross-origin at all. If your frontend and API are same-origin, or you authenticate with a token in an Authorization header rather than cookies, drop credentials entirely. For public, non-sensitive endpoints a plain wildcard is then fine:

Access-Control-Allow-Origin: *
# and NO Access-Control-Allow-Credentials header at all

2. If you genuinely need cookies cross-origin, replace * with a server-side allowlist and echo only a matching origin, never the wildcard.

Express:

const cors = require('cors');
const allowlist = new Set(['https://app.yourdomain.com']);

app.use(cors({
  origin(origin, cb) {
    if (!origin || allowlist.has(origin)) return cb(null, true);
    return cb(null, false);
  },
  credentials: true, // now paired with a specific origin, never '*'
}));

nginx, gate the credentialed header behind an allowlist match:

# in the http { } block
map $http_origin $cors_ok {
  default                       "";
  "https://app.yourdomain.com"  $http_origin;
}

location /api/ {
  add_header Access-Control-Allow-Origin $cors_ok always;
  add_header Access-Control-Allow-Credentials true always;
  add_header Vary Origin always;
}

The one rule to remember: Access-Control-Allow-Credentials: true may only ever appear next to a single, specific origin you chose, never * and never a blindly reflected one. If you do not need credentials, do not send that header, and a wildcard stays harmless.

Verify it

curl -sI -H "Origin: https://evil.example.com" https://yourdomain.com/api/ | grep -i access-control

You should never see Access-Control-Allow-Origin: * and Access-Control-Allow-Credentials: true in the same response, and a stranger origin like the one above must not be echoed back. A credentialed endpoint should return only an origin you put on the list, or no CORS headers at all.

Proof

The ApeCyber scanner flags this exact pairing passively, from the outside, reading only the response headers your server already sends, touching nothing. Bind credentials to a single named origin (or drop them, so a plain wildcard stays harmless) and the finding clears, a clean βˆ’20 off your posture score.