HIGH cors wildcardrailsjwt tokens

Cors Wildcard in Rails with Jwt Tokens

Cors Wildcard in Rails with Jwt Tokens — how this specific combination creates or exposes the vulnerability

In a Rails API that uses JWT-based authentication, a CORS configuration with an origin wildcard (origins: '*') can unintentionally expose authenticated routes to any web page. When credentials are allowed alongside a wildcard origin, browsers permit cross-origin requests that include cookies or authorization headers. Because JWTs are often sent in the Authorization: Bearer <token> header, a malicious site can make authenticated requests on behalf of a user if the backend does not validate the origin.

This combination is risky because the same-origin policy is relaxed by the wildcard, but the presence of JWTs in headers signals an authenticated context. An attacker can craft a page that calls your API endpoints, leveraging the permissive CORS rules to perform actions with the victim’s token. Even if the token is not stored in a cookie, the wildcard allows the request to proceed, and the server may treat it as valid because it does not check the Origin header against an allowlist.

For example, a Rails controller using skip_before_action :verify_authenticity_token and relying solely on JWT validation may still process requests from any origin if CORS permits it. Without explicit origin restrictions, an attacker can trigger cross-origin authenticated calls via embedded scripts or forms, leading to unauthorized actions or data access. This pattern is commonly seen in applications that expose user-specific endpoints (e.g., /api/users/me) without origin checks.

Additionally, preflight requests (OPTIONS) may return permissive headers like Access-Control-Allow-Origin: * and Access-Control-Allow-Headers: Authorization, signaling to browsers that cross-origin authenticated requests are acceptable. Once the preflight succeeds, the actual request with the JWT in the header is allowed, bypassing intended isolation between web origins.

Tools like middleBrick can detect such misconfigurations by scanning the API endpoints and inspecting CORS response headers alongside the authentication mechanisms in use. Its checks include identifying wildcard origins when authentication schemes like JWT are present, helping teams understand where their unauthenticated scan reveals risky exposure.

Jwt Tokens-Specific Remediation in Rails — concrete code fixes

To secure a Rails API using JWTs, configure CORS to explicitly specify allowed origins and avoid sending permissive headers for authenticated routes. Below are code examples that demonstrate a safe setup.

1. Configure a strict CORS policy in config/initializers/cors.rb

# config/initializers/cors.rb
Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins 'https://your-trusted-frontend.com', 'https://app.yourdomain.com'

    resource '*',
      headers: :any,
      methods: [:get, :post, :put, :patch, :delete, :options, :head],
      expose: ['X-CSRF-Token', 'X-Rate-Limit-Limit', 'X-Rate-Limit-Remaining'],
      max_age: 1728000
  end
end

Replace the origins with your frontend domains. Avoid '*' when authentication headers are used. The expose list should only include non-sensitive headers that the frontend needs to read.

2. Validate JWT and origin in the application controller

# app/controllers/application_controller.rb
class ApplicationController < ActionController::API
  before_action :authenticate_from_jwt
  before_action :cors_preflight_check

  private

  def authenticate_from_jwt
    header = request.headers['Authorization']
    token = header&.split(' ')&.last if header
    return head :unauthorized unless token&;present?

    # Example using knock or a custom decoder; adapt to your JWT library
    begin
      decoded = JWT.decode(token, Rails.application.secrets.secret_key_base, true, { algorithm: 'HS256' })
      @current_user = User.find(decoded[0]['user_id'])
    rescue JWT::DecodeError, ActiveRecord::RecordNotFound
      head :unauthorized
    end
  end

  def cors_preflight_check
    if request.method == 'OPTIONS'
      headers['Access-Control-Allow-Origin'] = request.headers['Origin'] || ''
      headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD'
      headers['Access-Control-Allow-Headers'] = 'Authorization, Content-Type'
      headers['Access-Control-Max-Age'] = '1728000'
      headers['Access-Control-Allow-Credentials'] = 'true'
      render plain: '', content_type: 'text/plain'
    end
  end
end

This ensures that only requests with a valid JWT and an allowed origin are processed. The cors_preflight_check method responds to OPTIONS requests with the requesting origin rather than a wildcard when credentials are involved.

3. Use a gem like rack-cors with request-based configuration

# config/initializers/cors.rb with request-based origin validation
Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins ->(request) { request.headers['Origin'] if request.headers['Origin'] =~ /\.yourdomain\.com$/ }

    resource '*',
      headers: :any,
      methods: [:get, :post, :put, :patch, :delete, :options, :head],
      max_age: 1728000
  end
end

This dynamic approach allows origins that match your domain pattern while rejecting unknown sources. Combined with JWT validation in the controller, it reduces the risk of cross-origin abuse.

Using middleBrick’s scans, teams can verify that CORS headers do not expose Access-Control-Allow-Origin: * when authentication mechanisms like JWT are active. The tool surfaces per-category findings and provides prioritized remediation guidance aligned with frameworks such as OWASP API Top 10.

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

Can I use 'Access-Control-Allow-Origin: *' with JWTs if I don't allow credentials?
No. Even without credentials, wildcard origins can expose authenticated endpoints if your frontend embeds tokens in headers. Use explicit origins to restrict which domains can access your API.
How does middleBrick help detect CORS issues with JWT configurations?
middleBrick scans response headers and runtime behavior to identify mismatches between CORS policy and authentication mechanisms, highlighting wildcard origins when JWTs or other authentication schemes are present.