Cors Wildcard in Grape with Basic Auth
Cors Wildcard in Grape with Basic Auth — how this specific combination creates or exposes the vulnerability
In Grape-based APIs, combining a CORS wildcard with HTTP Basic Auth can unintentionally expose authenticated endpoints to cross-origin requests. When Access-Control-Allow-Origin is set to * while credentials or authentication headers are required, browsers may allow cross-origin requests to include credentials depending on the request mode, potentially bypassing intended origin restrictions.
For requests that include authentication (e.g., Basic Auth via the Authorization header), a wildcard origin can enable a cross-origin attacker to make authenticated requests from a malicious site if the API also reflects or trusts the Origin header improperly. While Basic Auth sends credentials with every request, the browser’s CORS preflight and response header handling determine whether the response is made available to the JavaScript frontend. If Access-Control-Allow-Credentials is set to true alongside a wildcard origin, this violates the CORS specification and can lead to unauthorized cross-origin access to authenticated resources.
Grape does not enforce CORS by default; developers add CORS support via middleware such as rack-cors. Misconfiguration commonly includes:
- Setting
origins: '*'while also allowing credentials. - Using a dynamic origin matcher that echoes the request Origin without strict validation.
For example, a vulnerable Grape API might include CORS configuration like this:
require 'grape'
require 'rack/cors'
class PublicAPI < Grape::API
before do
headers['Access-Control-Allow-Origin'] = '*'
headers['Access-Control-Allow-Credentials'] = 'true'
end
resource :users do
desc 'Get current user, requires Basic Auth'
before { authenticate! }
get do
{ user: current_user }
end
end
end
use Rack::Cors do
allow do
origins '*'
resource '*',
headers: :any,
methods: [:get, :post, :options],
expose: ['Authorization']
end
end
In this configuration, the combination of origins '*' and Access-Control-Allow-Credentials: true is invalid per the CORS specification. A cross-origin site can trigger authenticated requests that include the Basic Auth header, and if the API’s response exposes headers or data to the originating page, sensitive information may be leaked.
Additionally, if the API reflects the Origin header into responses or allows arbitrary origins via a dynamic check, an attacker can craft a page that issues authenticated requests to the Grape endpoint from a victim’s browser. The browser will include the Authorization header (Base64-encoded credentials) with the request, and depending on CORS settings, the attacker may read the response.
To detect this class of issue, scanners perform unauthenticated CORS preflight and simple GET checks while looking for wildcard origins alongside authentication requirements. They also inspect whether Access-Control-Allow-Credentials is present and true when origins are not explicitly restricted.
Basic Auth-Specific Remediation in Grape — concrete code fixes
Remediation focuses on tightening CORS configuration and avoiding unsafe combinations with HTTP Basic Auth. Since Basic Auth credentials are sent with every request, the origin must be explicitly restricted and credentials should only be allowed when necessary.
Use a strict list of trusted origins instead of a wildcard. If your API is only consumed by a known frontend, specify those origins explicitly. Also, avoid setting Access-Control-Allow-Credentials to true when using a wildcard origin.
The following example demonstrates a secure CORS setup for a Grape API using Basic Auth:
require 'grape'
require 'rack/cors'
class SecureAPI < Grape::API
helpers do
def authenticate!
header['WWW-Authenticate'] = 'Basic realm="API"'
throw(:halt, [401, { error: 'Unauthorized' }.to_json])
end
def current_user
@current_user ||= begin
auth = request.env['HTTP_AUTHORIZATION']
return nil unless auth&.start_with?('Basic ')
encoded = auth.split(' ').last
userpass = Base64.strict_decode64(encoded)
user, pass = userpass.split(':', 2)
# Replace with secure credential verification
user == 'admin' && pass == 's3cret' ? user : nil
end
end
end
before do
authenticate! unless [OPTIONS].include?(request.request_method)
end
resource :users do
desc 'Get current user, requires Basic Auth'
before { authenticate! }
get do
{ user: current_user }
end
end
end
# config/initializers/cors.rb or equivalent setup
use Rack::Cors do
allow do
origins 'https://app.example.com', 'https://api.example.com'
resource '/api/*',
headers: :any,
methods: [:get, :post, :options],
expose: [],
max_age: 600
end
end
Key remediation steps:
- Specify exact origins in
originsinstead of'*'. - Do not set
Access-Control-Allow-Credentials: truewhen using wildcard origins; if credentials are required, restrict origins rigorously. - Ensure that the CORS middleware is placed before Grape routing so that headers are applied consistently.
- Validate the Origin header on the server side even when using a restricted list to prevent host-header-based bypasses.
For automated detection and ongoing compliance, integrate the middleBrick web dashboard or run the CLI tool (middlebrick scan <url>) to identify CORS misconfigurations. Teams using CI/CD can add the GitHub Action to fail builds if risk scores exceed thresholds, and the MCP Server can scan APIs directly from IDEs used by developers.
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 |