Cors Wildcard in Sinatra with Bearer Tokens
Cors Wildcard in Sinatra with Bearer Tokens — how this combination creates or exposes the vulnerability
A CORS wildcard (Access-Control-Allow-Origin: *) in Sinatra combined with Bearer token authentication creates a critical misconfiguration that can expose protected resources to unauthorized origins. When an endpoint validates tokens but also responds to any origin, a malicious site can make authenticated requests on behalf of a victim who possesses a valid token. The browser enforces CORS for cross-origin JavaScript, and a wildcard allows any domain to read the response if credentials or tokens are handled naively.
Consider a Sinatra route that checks a Bearer token but sets a permissive CORS header:
require 'sinatra'
require 'json'
before do
# Per request CORS header, overly permissive
headers 'Access-Control-Allow-Origin' => '*'
headers 'Access-Control-Allow-Methods' => 'GET, POST, OPTIONS'
headers 'Access-Control-Allow-Headers' => 'Authorization, Content-Type'
end
get '/api/data' do
auth = request.env['HTTP_AUTHORIZATION']
# naive Bearer check
if auth&& auth.start_with?('Bearer ')
# process request — token accepted
{ secret: 'top secret', user: 'alice' }.to_json
else
status 401
{ error: 'Unauthorized' }.to_json
end
end
The vulnerability arises because the wildcard origin allows a page hosted on https://evil.com to include this route via fetch or XMLHttpRequest. Even though the server validates the Bearer token, the response is delivered to the attacker’s JavaScript if the victim’s browser includes the token in an Authorization header. The wildcard signals that any origin is trusted, undermining origin-based isolation. This is especially dangerous for token-based APIs where the token is stored in browser-accessible JavaScript or where tokens are passed in headers from a compromised frontend.
In the context of API security scanning, this issue maps to BOLA/IDOR and Property Authorization checks. A scanner can detect the combination of permissive CORS and bearer-based authentication by cross-referencing the OpenAPI spec’s security schemes with the runtime CORS headers. A spec defining Bearer authentication but missing strict Access-Control-Allow-Origin controls will be flagged with high severity, as it enables unauthorized data access via browser-based scripts.
Additional risk occurs during preflight requests. If the server responds to OPTIONS with a wildcard origin and allows credentials-related headers without validating the origin, an attacker can craft a two-stage exploit: first, probe allowed methods and headers, then perform authenticated requests using the victim’s token. This pattern is consistent with CORS misconfigurations observed in real-world API breaches, where token validation is present but origin policy is unrestricted.
Bearer Tokens-Specific Remediation in Sinatra — concrete code fixes
Remediation focuses on tightening CORS policy and ensuring token checks remain authoritative without relying on permissive origins. Replace the wildcard with explicit origins and consider dynamic reflection only when necessary. Always pair CORS with proper authentication checks and avoid exposing sensitive data to untrusted origins.
1) Restrict origins instead of using a wildcard
require 'sinatra'
require 'json'
configure do
# Define allowed origins explicitly or via environment
set :allowed_origins, ['https://app.yourdomain.com', 'https://admin.yourdomain.com']
end
before do
origin = request.env['HTTP_ORIGIN']
allowed = settings.allowed_origins
if allowed.include?(origin)
headers 'Access-Control-Allow-Origin' => origin
headers 'Access-Control-Allow-Methods' => 'GET, POST, OPTIONS'
headers 'Access-Control-Allow-Headers' => 'Authorization, Content-Type'
headers 'Access-Control-Allow-Credentials' => 'true' if request.options?
end
if request.options?
# Preflight response
headers 'Access-Control-Max-Age' => '86400'
halt 200
end
end
get '/api/data' do
auth = request.env['HTTP_AUTHORIZATION']
halt 401, { error: 'Unauthorized' }.to_json unless auth&& auth.start_with?('Bearer ')
# Validate token against your auth provider here
{ secret: 'top secret', user: 'alice' }.to_json
end
By explicitly listing origins, you ensure only trusted frontends can read responses. The server reflects the requesting origin only when it matches an allowed entry, preventing arbitrary origins from receiving authenticated data.
2) Avoid credentials and wildcard together, and validate tokens rigorously
before do
origin = request.env['HTTP_ORIGIN']
allowed = settings.allowed_origins
if allowed.include?(origin)
headers 'Access-Control-Allow-Origin' => origin
headers 'Access-Control-Allow-Credentials' => 'true'
headers 'Access-Control-Allow-Methods' => 'GET, POST, OPTIONS'
headers 'Access-Control-Allow-Headers' => 'Authorization, Content-Type'
end
# Preflight handling as above
end
helpers do
def authenticate!
auth = request.env['HTTP_AUTHORIZATION']
halt 401, { error: 'Unauthorized' }.to_json unless auth&& auth.match?(/\ABeer\S+\s+(\S+)\z/)
token = $1
# Perform token validation — e.g., verify signature, scope, expiry
# For illustration, accept a specific test token
halt 403, { error: 'Forbidden' }.to_json unless token == 'valid_token_123'
end
end
get '/api/secure' do
authenticate!
{ data: 'protected resource' }.to_json
end
This approach removes the wildcard, adds explicit origin checks, and keeps token validation separate from CORS logic. It aligns with the principle of least privilege: origins are whitelisted, credentials are only sent to trusted sources, and tokens are validated before any data is returned.
In practice, combine this with an OpenAPI spec that declares the Bearer security scheme and documents allowed origins. MiddleBrick’s scanning can highlight the mismatch between a strict security scheme and a permissive CORS policy, guiding you toward compliant configurations.
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 setting Access-Control-Allow-Origin to * always break Bearer token security?
Should I include credentials when using a wildcard CORS policy?
Access-Control-Allow-Credentials: true with a wildcard origin. Browsers reject such combinations for security. Define specific origins when credentials are required.