HIGH dns rebindinggraperuby

Dns Rebinding in Grape (Ruby)

Dns Rebinding in Grape with Ruby — how this specific combination creates or exposes the vulnerability

DNS Rebinding is a client-side attack where a malicious webpage resolves a hostname to an internal IP address (e.g., 127.0.0.1), then quickly re-resolves the same hostname to a different IP, bypassing same-origin protections. When you build APIs with the Grape framework in Ruby, DNS Rebinding can expose internal services or bypass network-based access controls if the server trusts the Host header or uses request metadata for routing decisions.

Grape is a REST-like API framework that sits on Rack. In Ruby, the effective target for rebinding is often a Rack-based endpoint served by Grape, because the application may inspect request.host, request.headers, or use the Host header for internal routing or virtual-host logic. An attacker can serve a page that resolves a domain like internal.api.example.com first to 127.0.0.1, making the browser send authenticated requests to your Grape app on localhost. If the Grape app uses hostname-based allowlists or trusts the Host header without validation, the request may be processed as if it originated from an external, trusted source.

Consider a Grape endpoint that performs internal service discovery based on the Host header:

class InternalServiceAPI < Grape::API
  format :json

  # Risky: using request.host for routing or authorization
  route_param :service do
    get do
      target_host = params[:host] || request.host
      # If target_host is attacker-controlled via DNS rebinding,
      # internal host resolution may be bypassed.
      { resolved_target: target_host, status: 'ok' }
    end
  end
end

If an attacker crafts a page that makes requests to https://internal.api.example.com/service/foo?host=127.0.0.1, and the DNS for internal.api.example.com is rebindable, the browser may send the request to 127.0.0.1. The server-side code above would reflect the internal IP or hostname, potentially exposing internal endpoints or allowing SSRF-like behavior when combined with other weaknesses.

Grape apps behind reverse proxies or load balancers may also be vulnerable if the proxy normalizes the Host header and the app uses Ruby’s request object to derive internal decisions. The vulnerability is not in Grape itself but in how the Ruby application uses request metadata without additional validation or network segregation.

To detect DNS Rebinding in the context of Grape and Ruby, middleBrick performs active probes that attempt to infer whether a hostname can resolve to both public and private IPs during a single session. The scanner checks for inconsistencies in the Host header handling and flags endpoints that use untrusted request metadata in security-sensitive decisions.

Ruby-Specific Remediation in Grape — concrete code fixes

Remediation focuses on never trusting the Host header or any client-supplied hostname for routing, authorization, or internal resolution. In Ruby with Grape, validate and normalize host values against an explicit allowlist or use server-side configuration instead of request-derived values.

1. Avoid using request.host for routing or sensitive decisions. Instead, derive behavior from authenticated context or fixed configuration:

class SafeServiceAPI < Grape::API
  format :json

  # Safe: no reliance on request.host for routing
  resource :service do
    before do
      # Require authentication and use a service identifier that is not derived from Host
      error!('Unauthorized', 401) unless authenticated?
    end

    params do
      requires :service_id, type: String, desc: 'Service identifier'
    end

    get ':service_id' do
      service_id = params[:service_id]
      # Use server-side mapping or a controlled directory lookup
      service = find_service(service_id)
      { service: service.name, status: 'ok' }
    end
  end
end

2. Validate Host header or use a proxy-mode setting. If you must inspect the host, compare against a strict allowlist and reject unexpected values:

class ValidatedHostAPI < Grape::API
  format :json

  ALLOWED_HOSTS = ['api.example.com', 'www.example.com'].freeze

  before do
def validate_host
    unless ALLOWED_HOSTS.include?(request.host)
      error!('Forbidden host', 403)
    end
  end

  route_param :service do
    get do
      # Only proceed if host was validated
      { service: params[:service], host: request.host }
    end
  end
end

3. Harden Rack configuration and proxy settings. Ensure your Rack server or reverse proxy sets headers like X-Forwarded-Host consistently and that your Ruby app uses a trusted proxy configuration to avoid spoofing:

# config.ru
use Rack::RequestIP
# If behind a trusted proxy, set trusted proxies in your server (e.g., Puma/Thin config)
# and avoid parsing X-Forwarded-Host without strict validation.
run MyGrapeApp

4. Use server-side resolution for internal services. Instead of resolving hostnames on demand, use a service registry or environment variables that are not influenced by client-controlled DNS:

class InternalClient
  def self.resolve(name)
    # Map service names to fixed, internal endpoints
    endpoints = {
      'users'  => 'http://127.0.0.1:4001',
      'orders' => 'http://127.0.0.1:4002'
    }
    endpoints.fetch(name) { raise 'Unknown service' }
  end
end

By combining these practices—removing reliance on request.host, validating against a fixed allowlist, and using server-side service discovery—you reduce the attack surface for DNS Rebinding in Grape APIs built with Ruby.

middleBrick can help verify these fixes by scanning your endpoints and checking for Host header misuse and SSRF-like patterns. If you use continuous scanning with the Starter plan or higher, your Grape endpoints can be monitored on a schedule, and the Pro plan adds CI/CD integration to fail builds if risky patterns are detected.

Frequently Asked Questions

Can DNS Rebinding affect Grape APIs that don't use the Host header?
Yes, if the client-side page makes authenticated requests to your API domain, the browser will include credentials (cookies or tokens) regardless of whether the server uses the Host header. The risk is in server-side trust of client-supplied values; server-side validation and network segregation remain essential.
How can I test my Grape app for DNS Rebinding locally?
Set up a local domain (e.g., api.test) pointing to 127.0.0.1 in your hosts file, then write a simple HTML page that embeds an iframe or image pointing to https://api.test/endpoint and logs responses. Observe whether the server reflects internal hostnames or processes requests differently when the IP changes between DNS resolutions.