HIGH api key exposuresinatrasaml

Api Key Exposure in Sinatra with Saml

Api Key Exposure in Sinatra with Saml — how this specific combination creates or exposes the vulnerability

When a Sinatra application uses SAML for authentication, developers often focus on asserting user identity and roles and may inadvertently expose application-level secrets such as API keys. Api key exposure occurs when keys are embedded in views, passed to the browser, logged in plain text, or made reachable through misconfigured SAML endpoints or session handling.

In a Sinatra app, routes might load an API key from environment variables and pass it directly to a helper or template. If the route is accessible while the SAML session is not properly validated on every request, unauthenticated or insufficiently authenticated access can reveal the key. For example, a route like /settings that renders a key for client-side JavaScript can be reached if SAML session checks are missing or bypassed via a crafted SAML response or an unauthenticated endpoint that shares session state insecurely.

SAML-specific risks arise during authentication flows. If the Service Provider (SP) configuration in Sinatra does not validate signatures or properly handle the SAML response state, an attacker might force a login redirect or inject a crafted response that results in the app exposing sensitive data to the browser or logs. Middleware or helper methods that store API keys in the session without encryption, or that serialize keys into SAML attributes or NameID mappings, can inadvertently surface those keys in assertions or logs.

Additional exposure pathways include verbose logging of SAML responses where API keys are mistakenly included, or insecure use of callbacks where the Sinatra app returns or echoes tokens. Since SAML often introduces multiple identity assertions and attribute mappings, keys stored alongside user attributes in the session or in transient variables can be copied into browser-accessible contexts, such as JSON endpoints rendered without access controls.

Saml-Specific Remediation in Sinatra — concrete code fixes

Secure Sinatra applications using SAML by isolating secrets from identity flows, enforcing strict session validation, and ensuring SAML responses never expose sensitive values. Below are concrete, working examples that demonstrate safe patterns.

1. Keep API keys out of views and SAML assertions

Never render API keys in templates or include them in SAML attributes. Store keys in environment variables and access them only in server-side code that is protected by proper authentication and authorization checks.

# config/initializers/secrets.rb
ENV['API_KEY'] = ENV.fetch('API_KEY') { raise 'API_KEY is missing' }

# helpers/auth.rb
helpers do
  def current_user
    env['warden'].user
  end

  def require_saml_session!
    redirect to('/login') unless current_user&.saml_session_valid?
  end
end

# routes/settings.rb
require_relative '../helpers/auth'

before do
  require_saml_session!
end

get '/settings' do
  # Server-side only; key is never exposed to the browser
  { api_key: ENV['API_KEY'] }.to_json
end

2. Validate SAML responses and control attribute mapping

Ensure your SP configuration validates signatures and does not map sensitive values into SAML attributes. Use the saml gems with strict settings and avoid passing API keys through NameID or attributes.

# app.rb
require 'sinatra'
require 'saml' # e.g., ruby-saml
require 'securerandom'

SAML_SETTINGS = {
  idp_cert_fingerprint: ENV.fetch('IDP_CERT_FINGERPRINT'),
  issuer: ENV.fetch('SP_ENTITY_ID'),
  assertion_consumer_service_url: '/saml/callback',
  want_assertions_signed: true,
  want_name_id: false,
  name_id_format: 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress'
}

get '/saml/login' do
  request_id = SecureRandom.uuid
  redirect Saml::Idp::AuthnRequest.new(SAML_SETTINGS).request_url('https://idp.example.com/sso', request_id)
end

post '/saml/callback' do
  response = Saml::Response.new(params[:SAMLResponse], SAML_SETTINGS.merge(keep_assertion: false))
  halt 401 unless response.success?

  # Map only identity attributes, never API keys
  session[:user_email] = response.name_id
  session[:roles] = response.attributes['roles'] || []
  redirect to('/dashboard')
end

3. Avoid logging or echoing SAML data that may contain references to secrets

Configure logging to exclude SAML responses and ensure any debug endpoints do not echo tokens or keys. Treat SAML responses as opaque and validate before use.

# config/initializers/logging.rb
configure :production do
  configure do |config|
    config.log = lambda do |message|
      # Scrub SAML responses from logs
      ScrubSaml.call(message) unless message.to_s.include?('SAMLResponse')
    end
  end
end

# Middleware to prevent accidental exposure
class SamlScrubber
  def initialize(app)
    @app = app
  end

  def call(env)
    request = Rack::Request.new(env)
    if request.params['SAMLResponse']
      # Do not log or store raw responses
      env['rack.request.form_hash'] = {}
    end
    @app.call(env)
  end
end

use SamlScrubber

4. Enforce per-request authorization for sensitive endpoints

Even when authenticated via SAML, explicitly check permissions before exposing any sensitive data or operations. Do not rely solely on SAML session presence for authorization to access API keys or admin functions.

# routes/admin.rb
before '/admin/*' do
  require_saml_session!
  redirect to('/') unless current_user&.admin?
end

get '/admin/api_key' do
  # Only accessible to admins; key remains server-side
  { rotate: true }.to_json
end

Frequently Asked Questions

How can I prevent API keys from being exposed through SAML attributes in Sinatra?
Do not map API keys into SAML attributes or NameID. Keep keys in environment variables and access them server-side only after validating the SAML session. Configure your SAML gem with want_assertions_signed: true and avoid passing secrets in assertions.
What should I do if my Sinatra logs contain SAML responses that might expose sensitive data?
Scrub SAML responses from logs by using a logging middleware that removes or hashes raw SAMLResponse values. Ensure any debug or error endpoints do not echo SAML data, and treat SAML responses as opaque — validate and extract only identity attributes you need.