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 ID | Name | Severity |
|---|---|---|
| CWE-200 | Exposure of Sensitive Information | HIGH |
| CWE-209 | Error Information Disclosure | MEDIUM |
| CWE-213 | Exposure of Sensitive Information Due to Incompatible Policies | HIGH |
| CWE-215 | Insertion of Sensitive Information Into Debugging Code | MEDIUM |
| CWE-312 | Cleartext Storage of Sensitive Information | HIGH |
| CWE-359 | Exposure of Private Personal Information (PII) | HIGH |
| CWE-522 | Insufficiently Protected Credentials | CRITICAL |
| CWE-532 | Insertion of Sensitive Information into Log File | MEDIUM |
| CWE-538 | Insertion of Sensitive Information into Externally-Accessible File | HIGH |
| CWE-540 | Inclusion of Sensitive Information in Source Code | HIGH |
Frequently Asked Questions
Does using credentials: true with a wildcard origin make CORS secure?
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?
X-API-Key) and pair with strict CORS origins and server-side validation.