HIGH cors wildcardrailsapi keys

Cors Wildcard in Rails with Api Keys

Cors Wildcard in Rails with Api Keys — how this specific combination creates or exposes the vulnerability

A CORS wildcard (Access-Control-Allow-Origin: *) combined with API key authentication in a Rails API can unintentionally expose protected resources to any origin that possesses a valid key. In Rails, wildcard CORS is typically set via config/initializers/cors.rb using origins '*', while API keys are often validated before CORS headers are applied. If the key validation succeeds but the response still includes a wildcard, any webpage under an attacker’s control can make authenticated requests on behalf of a victim who possesses or leaks the key. Because the browser enforces the same-origin policy, it will accept the response only if the server explicitly allows the requesting origin; a wildcard circumvents this restriction by permitting any origin to read the response.

This becomes particularly dangerous when API keys are embedded in client-side JavaScript or leaked in logs and referrer headers. An attacker can host a malicious page that iterates over known endpoints, using the victim’s browser to send the key with each request. Since the server responds with Access-Control-Allow-Origin: *, the attacker’s JavaScript can read the responses and exfiltrate sensitive data. The interaction between CORS and authentication is nuanced: CORS is a browser-enforced mechanism, so non-browser clients are not restricted; however, for browser-based clients, a wildcard with key-based auth defeats the isolation that same-origin policies are meant to provide.

Consider a Rails API that uses header-based API keys and a permissive CORS configuration:

# config/initializers/cors.rb
Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins '*'
    resource '*',
      headers: :any,
      methods: %i[get post put delete],
      expose: ['X-Rate-Limit-Limit', 'X-Rate-Limit-Remaining']
  end
end

If the controller authenticates via request.headers['Authorization']&.start_with?('ApiKey ') && validate_key, a successful validation will still return wildcard CORS headers. This means any site that can trick a user’s browser into including the key (e.g., via a forged link or compromised subdomain) can read the responses. OWASP API Top 10 highlights broken authentication and excessive data exposure in this context; unchecked wildcard CORS with keyed endpoints maps directly to these risks.

During a middleBrick scan, such misconfigurations appear in the findings with severity and remediation guidance, helping teams detect insecure CORS deployments before they are exploited. The scanner evaluates the intersection of authentication mechanisms and CORS policy to identify cases where permissive settings undermine key-based protections.

Api Keys-Specific Remediation in Rails — concrete code fixes

To secure Rails APIs that use API keys, align CORS policy with the principle of least privilege. Instead of a wildcard, explicitly list trusted origins. This prevents malicious sites from reading responses even when a valid API key is present. Below are concrete, syntactically correct configurations and code examples.

1. Restrict origins in CORS initializer

Replace origins '*'' with specific frontend origins. If your frontend is served from https://app.example.com and your admin console from https://admin.example.com, configure accordingly:

# config/initializers/cors.rb
Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins 'https://app.example.com', 'https://admin.example.com'
    resource '*',
      headers: :any,
      methods: %i[get post put delete],
      expose: ['X-Rate-Limit-Limit', 'X-Rate-Limit-Remaining'],
      credentials: true
  end
end

Setting credentials: true ensures that cookies and HTTP authentication headers (including your custom API key header) are included in cross-origin requests, while not using a wildcard keeps the policy tight.

2. Validate API keys before CORS headers are applied

Ensure authentication runs early and that CORS responses do not leak information about valid keys. In your controller or a before_action, perform key validation and only then allow the request to proceed:

# app/controllers/application_controller.rb
class ApplicationController < ActionController::API
  before_action :authenticate_api_key!

  private

  def authenticate_api_key!
    key = request.headers['X-API-Key'] || request.headers['Authorization']&.split(' ')&.last
    unless key && VALID_KEYS.include?(key)
      render json: { error: 'Unauthorized' }, status: :unauthorized
    end
  end
end

3. Use Rails credentials or environment variables for key storage

Avoid hardcoding keys. Store them in config/credentials.yml.enc or environment variables, and reference them securely:

# config/credentials.yml.enc (decrypt with EDITOR="code --wait" rails credentials:edit)
api_keys:
  client_app: ${CLIENT_API_KEY}
  internal_service: ${INTERNAL_API_KEY}

Then load and compare in the authenticator:

# config/initializers/api_keys.rb
VALID_KEYS = Rails.application.credentials.dig(:api_keys, :client_app) || []

4. Combine with rate limiting and monitoring

Even with correct CORS and key validation, add rate limiting to mitigate abuse if a key is leaked:

# Gemfile
gem 'rack-attack'

# config/initializers/rack_attack.rb
class Rack::Attack
  throttle('api_key/ip', limit: 300, period: 60) do |req|
    req.headers['X-API-Key'] || req.ip
  end
end

These steps ensure that API keys remain protected and that CORS does not become a vector for unauthorized data reading in browser-based clients.

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 using credentials: true with a wildcard origin make CORS secure?
No. If you specify credentials: true but keep origins '*', browsers will reject the request because wildcard origins are not allowed when credentials are included. You must list explicit origins instead of a wildcard.
Can API keys in URL query parameters be safely used with permissive CORS?
Avoid placing API keys in query parameters. They can leak in logs, referrers, and browser history. Use headers (e.g., X-API-Key) and pair with strict CORS origins and server-side validation.