HIGH ssrf server sidegrapebasic auth

Ssrf Server Side in Grape with Basic Auth

Ssrf Server Side in Grape with Basic Auth — how this specific combination creates or exposes the vulnerability

Server Side Request Forgery (SSRF) in a Grape API combined with Basic Authentication can amplify risk by allowing an authenticated context to reach internal services that would otherwise be unreachable. Grape is a Ruby web framework that lets you define API endpoints and authentication hooks. When you add Basic Auth via before hooks, the endpoint expects an Authorization header, but if the downstream HTTP client is not tightly constrained, an attacker can supply a malicious URL that causes the server to open connections to internal addresses (e.g., 127.0.0.1, 169.254.169.254, or internal Kubernetes services).

Basic Auth itself does not cause SSRF, but it changes the exposure surface. An endpoint that validates presence of credentials can still forward requests to arbitrary hosts, and internal services often trust requests coming with service account credentials. For example, a health-check or metadata endpoint that uses Net::HTTP with user-supplied input can be abused to enumerate internal infrastructure. This is especially dangerous when the endpoint performs outbound requests without validating the target host against a denylist or enforcing a strict allowlist of domains.

In a Grape API, if you parse params and pass them directly to an HTTP client without restricting the host, port, or scheme, SSRF becomes feasible even when Basic Auth is enforced. Attack patterns include probing internal metadata services, connecting to Redis or Elasticsearch on localhost, or abusing internal AWS instance metadata. Because the scan tests unauthenticated attack surfaces, middleBrick flags SSRF even when Basic Auth headers are present, since the vulnerability lies in URL handling, not credential validation.

Consider the following vulnerable Grape endpoint that demonstrates the issue:

require 'grape'
require 'net/http'
require 'uri'

class V1 < Grape::API
  format :json

  before do
    authenticate!
  end

  helpers do
    def authenticate!
      env['HTTP_AUTHORIZATION'] || error!('Unauthorized', 401)
    end
  end

  get :fetch do
    uri = URI(params[:url])
    response = Net::HTTP.get_response(uri)
    { status: response.code, body: response.body }
  end
end

In this example, a request with a valid Basic Auth header but a malicious value for params[:url] (such as http://169.254.169.254/latest/meta-data/) can lead to SSRF. middleBrick detects such patterns during runtime testing and highlights SSRF alongside the authentication context, enabling you to correlate findings with the presence of Basic Auth.

Basic Auth-Specific Remediation in Grape — concrete code fixes

To mitigate SSRF in Grape endpoints that use Basic Auth, you must validate and sanitize the target URL before making outbound requests. Combine host allowlisting, port restrictions, and URI normalization to reduce risk. Do not rely solely on authentication to protect against SSRF.

Below is a secure Grape endpoint that demonstrates safe practices:

require 'grape'
require 'net/http'
require 'uri'

class SecureApi < Grape::API
  format :json

  ALLOWED_HOSTS = %w[api.example.com internal.service.local].freeze
  ALLOWED_PORTS = [443, 80].freeze

  before do
    authenticate!
  end

  helpers do
    def authenticate!
      # Basic Auth validation using credentials comparison
      auth = env['HTTP_AUTHORIZATION']
      return unless auth&.start_with?('Basic ')
      decoded = Base64.strict_decode64(auth.sub('Basic ', ''))
      # In production, compare against secure credential store
      halt 401, { error: 'Invalid credentials' }.to_json unless valid_credentials?(decoded)
    end

    def valid_credentials?(cred)
      # Example: compare against environment variables
      user, pass = cred.split(':', 2)
      user == ENV['API_USER'] && pass == ENV['API_PASS']
    end

    def safe_fetch(url_str)
      uri = URI.parse(url_str)
      unless ALLOWED_HOSTS.include?(uri.host)
        raise ArgumentError, 'Host not allowed'
      end
      unless ALLOWED_PORTS.include?(uri.port)
        raise ArgumentError, 'Port not allowed'
      end
      uri = URI::HTTPS === uri ? uri : uri.dup.tap { |u| u.scheme = 'https' }
      response = Net::HTTP.get_response(uri)
      { status: response.code, body: response.body }
    rescue URI::InvalidURIError, ArgumentError => e
      { error: e.message }
    end
  end

  get :fetch do
    result = safe_fetch(params[:url])
    present result
  end
end

This approach restricts outbound requests to known hosts and ports, enforces HTTPS, and avoids passing raw user input to the HTTP client. middleBrick recognizes such controls during scans and reports reduced risk when host and port validation are in place.

Additionally, consider using a vetted HTTP client library that supports proxying and connection pooling, and avoid following redirects to internal destinations. Regularly review logs for unexpected outbound connections and integrate middleBrick into your CI/CD pipeline to catch regressions early.

Frequently Asked Questions

Can SSRF occur even when Basic Auth is enforced?
Yes. Basic Auth validates credentials but does not restrict where the server can connect. If the endpoint forwards requests to arbitrary URLs, SSRF remains possible.
Does middleBrick detect SSRF in authenticated contexts?
middleBrick scans the unauthenticated attack surface and can detect SSRF patterns even when Basic Auth headers are present, because the vulnerability is in URL handling, not credential validation.