HIGH cors wildcardbearer tokens

Cors Wildcard with Bearer Tokens

How CORS Wildcard Manifests in Bearer Tokens

When an API uses Bearer tokens for authentication, the token is typically transmitted in the Authorization header. If the server’s CORS policy is misconfigured with a wildcard origin (Access-Control-Allow-Origin: *) and also lists the Authorization header in Access-Control-Allow-Headers, a malicious web site can cause a victim’s browser to send a cross‑origin request that includes the bearer token and read the response.

The attack flow is:

  1. Victim logs into the legitimate API and receives a Bearer token (e.g., eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…).
  2. Victim visits an attacker‑controlled site that runs JavaScript.
  3. The attacker’s script creates an XMLHttpRequest or fetch call to https://api.example.com/profile with the Authorization header set to Bearer <token>.
  4. Because the request includes a custom header, the browser issues a preflight OPTIONS request.
  5. The API responds with Access-Control-Allow-Origin: * and Access-Control-Allow-Headers: Authorization. Since the origin is a wildcard and no credentials are required (the token is not a cookie), the browser allows the actual request.
  6. The request reaches the API, the bearer token is validated, and the API returns sensitive data (e.g., user profile). The attacker’s script can now read that data.

This pattern appears in any code path where the API validates a Bearer token before returning data, such as:

  • GET /user/me – returns the authenticated user’s record.
  • POST /orders – creates an order after checking the token.
  • GET /api/v1/resources/:id – returns a resource if the token grants access.

The vulnerability is not specific to any language; it shows up in Express.js, Django REST Framework, Spring Boot, or any framework that lets developers configure CORS globally.

Bearer Tokens‑Specific Detection

Detecting this issue requires checking two related CORS response headers together with the presence of an Authorization header in the allowed list. middleBrick performs this check automatically during its 12‑parallel security scans.

When you submit a URL (e.g., https://api.example.com) via the dashboard, CLI, or GitHub Action, middleBrick:

  • Sends an OPTIONS request to each discovered endpoint.
  • Examines the Access-Control-Allow-Origin and Access-Control-Allow-Headers headers.
  • Flags a finding if:
    • Access-Control-Allow-Origin is exactly * (wildcard).
    • Access-Control-Allow-Headers contains Authorization (case‑insensitive) or is set to *.
  • Assigns a severity based on the endpoint’s sensitivity (e.g., endpoints that return user data or perform state‑changing actions receive a higher severity).

Example CLI output (truncated for clarity):

$ middlebrick scan https://api.example.com
Scanning... (12 checks in parallel)

[+] CORS Misconfiguration – High
    Endpoint: GET /user/me
    Issue: Access-Control-Allow-Origin: *
    Access-Control-Allow-Headers: Authorization, Content-Type
    Impact: Attacker site can read bearer‑token‑protected data.
    Remediation: Restrict origin to trusted domains or remove Authorization from allowed headers.

Security Score: C (68/100)

The same detection appears in the web dashboard under the “Findings” tab, and in the GitHub Action as a check that can fail a build if the score drops below a threshold you define (e.g., fail on any “High” or higher finding). The MCP Server integration lets you trigger a scan directly from your IDE, showing the CORS warning alongside other issues before you commit code.

Bearer Tokens‑Specific Remediation

The fix is to tighten the CORS policy so that either the origin is not a wildcard when the Authorization header is allowed, or the Authorization header is removed from the allowed list for wildcard origins. Below are language‑specific examples using the native libraries most teams already rely on.

Node.js / Express with the cors package

Incorrect (wildcard + Authorization):

const cors = require('cors');
app.use(cors({
  origin: '*',
  methods: ['GET','POST'],
  allowedHeaders: ['Authorization','Content-Type']
}));

Correct – restrict origin to known trusted origins:

const cors = require('cors');
const allowedOrigins = ['https://app.example.com', 'https://portal.example.com'];
app.use(cors({
  origin: function (origin, callback) {
    // allow requests with no origin (like mobile apps or curl)
    if (!origin) return callback(null, true);
    if (allowedOrigins.indexOf(origin) !== -1) {
      return callback(null, true);
    }
    const msg = 'The CORS policy for this site does not allow access from the specified Origin.';
    return callback(new Error(msg), false);
  },
  methods: ['GET','POST'],
  allowedHeaders: ['Content-Type'] // Authorization removed; token sent via cookie or same‑site header
}));

If you must keep the Authorization header (e.g., for SPA that cannot use cookies), lock down the origin:

app.use(cors({
  origin: allowedOrigins,
  methods: ['GET','POST'],
  allowedHeaders: ['Authorization','Content-Type']
}));

Python / Django REST Framework

Incorrect (global wildcard):

# settings.py
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_HEADERS = (
    'authorization',
    'content-type',
)

Correct – whitelist origins and keep Authorization only when needed:

# settings.py
CORS_ORIGIN_ALLOW_ALL = False
CORS_ORIGIN_WHITELIST = (
    'https://app.example.com',
    'https://portal.example.com',
)
CORS_ALLOW_HEADERS = (
    'authorization',  # keep if your frontend truly needs to send it
    'content-type',
))

If you prefer not to send the token via a custom header, switch to an HttpOnly, SameSite=Strict cookie and remove authorization from CORS_ALLOW_HEADERS.

Java / Spring Boot

Incorrect (global registry):

@Configuration
public class CorsConfig {
    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**")
                        .allowedOrigins("*")
                        .allowedHeaders("Authorization","Content-Type");
            }
        };
    }
}

Correct – restrict origins:

@Configuration
public class CorsConfig {
    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**")
                        .allowedOrigins("https://app.example.com","https://portal.example.com")
                        .allowedHeaders("Authorization","Content-Type");
            }
        };
    }
}

Alternatively, if you want to keep the wildcard for public resources, exclude the Authorization header from allowedHeaders for those mappings.

After applying any of these fixes, re‑run middleBrick (via CLI, dashboard, GitHub Action, or MCP Server) to confirm the CORS finding disappears and the security score improves.

Related CWEs: dataExposure

CWE IDNameSeverity
CWE-200Exposure of Sensitive Information HIGH
CWE-209Error Information Disclosure MEDIUM
CWE-213Exposure of Sensitive Information Due to Incompatible Policies HIGH
CWE-215Insertion of Sensitive Information Into Debugging Code MEDIUM
CWE-312Cleartext Storage of Sensitive Information HIGH
CWE-359Exposure of Private Personal Information (PII) HIGH
CWE-522Insufficiently Protected Credentials CRITICAL
CWE-532Insertion of Sensitive Information into Log File MEDIUM
CWE-538Insertion of Sensitive Information into Externally-Accessible File HIGH
CWE-540Inclusion of Sensitive Information in Source Code HIGH

Frequently Asked Questions

Does a wildcard CORS policy always lead to a bearer‑token theft?
No. The risk appears only when the server also lists the Authorization header (or *) in Access-Control-Allow-Headers. If the header is not allowed, the browser will block the request before it can include the token, so the token cannot be read by an attacker.
Can I still use bearer tokens with a strict CORS policy?
Yes. Bearer tokens work fine when the CORS policy specifies exact origins (or uses a dynamic origin check) and either omits the Authorization header from the allowed list or keeps it only when the origin is whitelisted. Many SPAs store the token in memory and attach it to requests; as long as the server trusts the origin, the token is sent and validated normally.