HIGH ssrf server sidegraperuby

Ssrf Server Side in Grape (Ruby)

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

Server Side Request Forgery (SSRF) in a Grape API built with Ruby occurs when an attacker can coerce the server into making arbitrary outbound HTTP requests from the host running the Ruby process. Because Grape encourages building rich endpoints with flexible parameter handling, it is common to forward query values into HTTP clients without strict validation. In Ruby, common libraries such as Net::HTTP, HTTParty, or Faraday are frequently used inside resource actions. If user input (e.g., a URL or host parameter) is passed directly to these clients, an attacker can reach internal metadata services, file:// or gopher:// endpoints, or other internal listeners that are not exposed externally.

Grape resources typically define routes and helpers that make it easy to extract params and perform requests inline. For example, a developer might write a proxy or webhook integration that accepts a target URL from the client. Without a strict allowlist or hostname validation, an attacker can supply internal IPs (169.254.169.254 for AWS metadata), localhost services, or docker internal DNS names to probe the runtime environment. The Ruby runtime does not inherently prevent these internal connections, so SSRF becomes a practical risk when input is trusted.

Additionally, Ruby on Rails or other frameworks integrated with Grape may introduce further SSRF vectors via ActiveJob, background workers, or service objects that reuse the same HTTP client logic. MiddleBrick’s checks for SSRF and related patterns help surface these risks by correlating OpenAPI specifications with runtime behavior, ensuring that endpoints accepting free-form URLs are flagged for review. Understanding how Grape routes, parameter coercion, and Ruby HTTP clients interact is essential to designing controls that prevent SSRF in production.

Ruby-Specific Remediation in Grape — concrete code fixes

Remediation focuses on strict input validation, allowlisting, and avoiding direct use of user-controlled data in HTTP requests. In Grape, define strong parameter rules and validate hostnames or IPs before any network call. Below are concrete, safe patterns for common Ruby HTTP clients used in Grape resources.

1) Use a strict hostname allowlist and reject private/reserved IPs

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

class ProxyResource < Grape::API
  ALLOWED_HOSTS = %w[api.example.com files.example.com]

  helpers do
    def safe_uri(input)
      uri = URI.parse(input)
      unless uri.respond_to?(:host) && ALLOWED_HOSTS.include?(uri.host)
        fail ArgumentError, 'Host not allowed'
      end
      # Ensure no embedded credentials or alternate ports that change behavior
      uri.port = 443 if uri.scheme == 'https'
      uri
    rescue URI::InvalidURIError
      fail ArgumentError, 'Invalid URI'
    end
  end

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

This pattern validates the hostname against an allowlist and normalizes the port, reducing SSRF risk while still supporting legitimate use cases.

2) Use a whitelisted set of schemes and disable dangerous protocols

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

class SafeProxyResource < Grape::API
  ALLOWED_SCHEMES = %w[https http]

  helpers do
    def sanitize_url(input)
      uri = URI.parse(input)
      unless ALLOWED_SCHEMES.include?(uri.scheme)
        fail ArgumentError, 'Scheme not allowed'
      end
      # Block internal IPs and reserved ranges
      ip = Resolv.getaddress(uri.host) rescue nil
      if ip && IPAddr.new('10.0.0.0/8').include?(IPAddr.new(ip))
        fail ArgumentError, 'Private IP not allowed'
      end
      uri
    rescue Resolv::ResolvError, URI::InvalidURIError, ArgumentError
      fail ArgumentError, 'Invalid or unsafe target'
    end
  end

  get 'fetch-safe' do
    target = sanitize_url(params[:url])
    response = Net::HTTP.get_response(target)
    { status: response.code, headers: response.to_hash, body: response.body }
  end
end

3) If using Faraday, avoid passing raw user input to the connection URL and prefer adapter-level timeouts and a strict proxy bypass for internal addresses

require 'grape'
require 'faraday'

class FaradayResource < Grape::API
  ALLOWED_HOSTS = %w[api.example.com]

  get 'fetch-faraday' do
    target_host = URI(params[:url]).host
    unless ALLOWED_HOSTS.include?(target_host)
      fail ArgumentError, 'Host not allowed'
    end

    conn = Faraday.new(url: params[:url]) do |faraday|
      faraday.request :url_encoded
      faraday.response :logger
      faraday.adapter Faraday.default_adapter
    end
    response = conn.get
    { status: response.status, body: response.body }
  end
end

These examples emphasize validation at the resource layer, avoiding blind concatenation of user input, and using Ruby standard libraries safely. Combined with MiddleBrick’s scans for SSRF and related findings, these practices reduce the likelihood of unintended internal network exposure in Grape-based Ruby APIs.

Frequently Asked Questions

Can SSRF be tested safely using middleBrick?
Yes. middleBrick performs black-box testing for SSRF during the scan (12 checks in parallel). It does not exploit or modify systems; it detects whether inputs can influence internal HTTP calls and reports findings with remediation guidance.
Does middleBrick fix SSRF findings automatically?
No. middleBrick detects and reports, providing prioritized findings and remediation guidance. It does not fix, patch, block, or remediate. Apply Ruby-specific validation patterns in Grape to address identified issues.