HIGH api key exposuregrapemssql

Api Key Exposure in Grape with Mssql

Api Key Exposure in Grape with Mssql — how this specific combination creates or exposes the vulnerability

Grape is a REST-like API micro-framework for Ruby projects, commonly used to build endpoints that return resources or perform actions. When a Grape API interacts with Microsoft SQL Server via the tiny_tds or activerecord-sqlserver-adapter, developers often embed connection strings or API keys directly in route handlers or helper methods. This pattern becomes a critical exposure when error handling is insufficient or when debug endpoints are left in production.

Consider a Grape endpoint that authenticates a request and then queries a Microsoft SQL Server instance using a connection string that contains an API key or database credential. If the endpoint does not properly sanitize inputs or handle exceptions, an attacker can trigger verbose error messages that reveal the connection string, including the embedded API key. For example, a malformed query or an intentional SQL injection attempt can cause TinyTds::Error or ActiveRecord::StatementInvalid to surface the full connection string in the response body.

Additionally, if the Grape API exposes administrative or diagnostic routes (for example, a route that runs SELECT @@VERSION or returns table metadata), these endpoints can unintentionally leak sensitive configuration details. When these routes are combined with weak authentication or missing authorization checks, an unauthenticated attacker can harvest API keys or connection details that grant access to backend systems.

Another vector specific to the Grape + Mssql combination involves logging. If the application logs full SQL statements or connection details at debug level and those logs are accessible via an endpoint or through log aggregation tools, an API key embedded in the connection string can be exposed through log disclosure. This often occurs when developers use dynamic SQL construction with string interpolation instead of parameterized queries, inadvertently including secrets in log entries that may be surfaced by debugging endpoints.

During a middleBrick scan, which tests the unauthenticated attack surface using parallel checks including Input Validation, Data Exposure, and Unsafe Consumption, such exposures are identified when responses reveal connection strings, stack traces with sensitive data, or endpoints that return configuration details. The LLM/AI Security checks further ensure that no system prompt leakage or output containing API keys occurs in any generated responses, which is especially relevant if the API interacts with language models using keys stored in the same environment.

Mssql-Specific Remediation in Grape — concrete code fixes

Remediation focuses on removing hard-coded keys from Grape route logic, using secure configuration management, and ensuring SQL interactions do not expose sensitive data. Below are concrete, Mssql-specific examples that you can apply in a Grape API.

1. Use environment variables and secure configuration

Never embed API keys or connection strings in route files. Load them from environment variables at runtime.

# config/initializers/db.rb
DB_CONFIG = {
  adapter: 'sqlserver',
  host: ENV['MSSQL_HOST'],
  port: ENV['MSSQL_PORT'] || 1433,
  database: ENV['MSSQL_DATABASE'],
  username: ENV['MSSQL_USERNAME'],
  password: ENV['MSSQL_PASSWORD'],
  encryption: { encrypt: true, trust_server_certificate: false }
}

# Use ActiveSupport::Cache::MemoryStore or a secure vault in production
require 'active_support/core_ext/hash/indifferent_access'
DB_CONFIG = ActiveSupport::HashWithIndifferentAccess.new(DB_CONFIG)

2. Parameterized queries to prevent injection and avoid logging sensitive data

Always use parameterized queries instead of string interpolation. This prevents SQL injection and avoids accidentally logging sensitive values.

# app/api/v1/users.rb
require 'json'
require 'tiny_tds'

class UsersAPI < Grape::API
  format :json

  helpers do
    def db_client
      @db_client ||= TinyTds::Client.new(
        host: ENV['MSSQL_HOST'],
        port: ENV['MSSQL_PORT'] || 1433,
        database: ENV['MSSQL_DATABASE'],
        username: ENV['MSSQL_USERNAME'],
        password: ENV['MSSQL_PASSWORD'],
        encryption: { encrypt: true, trust_server_certificate: false }
      )
    end
  end

  get '/users/:user_id' do
    user_id = params[:user_id].to_i
    # Parameterized query: values are passed separately, not interpolated
    result = db_client.execute(
      'SELECT id, email, role FROM users WHERE id = @id',
      id: user_id
    )
    row = result.first
    error!('Not found', 404) unless row
    { id: row['id'], email: row['email'], role: row['role'] }
  rescue TinyTds::Error => e
    # Log generic errors only; do not include connection details or SQL
    Rails.logger.error("Database error: #{e.message}")
    error!('Internal server error', 500)
  end
end

3. Secure error handling to prevent verbose responses

Ensure Grape does not return stack traces or database details. Use a generic error handler and avoid exposing Mssql internal messages.

# app/api/base.rb
class BaseAPI < Grape::API
  rescue_from ::StandardError do |e|
    # Log full error for internal monitoring, but return generic message
    Rails.logger.error("Unhandled exception: #{e.class} - #{e.message}")
    Rails.logger.error(e.backtrace.join("\n"))
    error!({ error: 'Internal server error' }, 500)
  end

  rescue_from TinyTds::Error do |e
    Rails.logger.error("Mssql error: #{e.message}")
    error!({ error: 'Database error' }, 500)
  end
end

4. Disable debug endpoints and restrict diagnostic routes

Remove or protect routes that expose server or configuration details. If you must keep them, require authentication and scope them to internal networks.

# app/api/v1/internal.rb
class InternalAPI < Grape::API
  before { authenticated_only! } # your own auth helper

  # Keep diagnostic routes behind auth and never return sensitive config
  get '/health' do
    { status: 'ok' }
  end

  # Avoid returning SQL version or schema details in production
  # get '/debug/version' do
  #   client = TinyTds::Client.new(ENV['MSSQL_CONNECTION'])
  #   client.execute('SELECT @@VERSION').first
  # end
end

5. Secure logging practices

Ensure logs do not contain connection strings or API keys. Filter sensitive parameters and avoid logging full SQL statements with values.

# config/initializers/filter_parameter_logging.rb
Rails.application.config.filter_parameters += [:password, :connection_string, :api_key]

# In your Grape rescue blocks, avoid logging raw SQL with values:
# BAD: Rails.logger.info("Query: SELECT * FROM users WHERE api_key = '#{ENV['API_KEY']}'")
# GOOD: Rails.logger.info("Query executed with parameterized inputs")

Frequently Asked Questions

Can middleBrick detect API key exposure in Grape endpoints that use Mssql?
Yes. middleBrick scans input validation and data exposure paths. It identifies responses that may reveal connection strings or API keys, including stack traces or verbose Mssql errors, without relying on internal architecture details.
Does middleBrick test LLM endpoints that might output API keys stored in Mssql-connected services?
Yes. The LLM/AI Security checks scan for system prompt leakage and output data such as API keys or PII that could be returned by an LLM integration, helping catch inadvertent exposure through AI-assisted features that query Mssql-backed services.