HIGH open redirectgrapemongodb

Open Redirect in Grape with Mongodb

Open Redirect in Grape with Mongodb — how this specific combination creates or exposes the vulnerability

An open redirect in a Grape API that uses MongoDB for user or configuration data occurs when an endpoint accepts a user-supplied URL or host value and then redirects the client to that location without strict validation. If the application stores redirect URIs, return URLs, or referrer-like values in MongoDB, and later uses those values to construct a redirect response, an attacker who can inject or influence a document in the collection may be able to redirect users to arbitrary destinations.

For example, consider an OAuth or post-login flow where a client passes a redirect_to query parameter. The server may look up a default landing page from MongoDB based on the client identifier, then redirect to the user-supplied value if present. If the stored redirect value is not canonicalized and validated, an attacker who can modify a MongoDB document (e.g., via a compromised admin account or an IDOR/BOLA bug) can set a malicious redirect target that later users are sent to. Even without direct write access, an open redirect may be possible if the application trusts user-controlled fields when building the redirect URL, such as concatenating a hostname from a MongoDB document with a path provided by the client.

Grape routes typically handle parameters via request params and may construct Location headers using values from MongoDB. Because MongoDB documents can contain nested fields and flexible schemas, an attacker might leverage stored URLs or hosts to poison the redirect logic. Common patterns include storing callback URLs for integrations or multi-tenant configurations. If the API does not validate that the redirect target belongs to a trusted set of domains, the API effectively becomes a redirector for phishing or malware distribution sites. This becomes more impactful when combined with other findings such as IDOR or BOLA, where an attacker can read or alter documents that affect redirect behavior.

In a security scan, this pattern is flagged as an open redirect because the Location header is derived from data that is not strictly constrained to safe, expected values. Even if the redirect is client-side (e.g., JavaScript window.location), storing the destination in MongoDB and failing to enforce strict allowlists or canonicalization enables an attacker to control the final URL seen by users. The presence of MongoDB as a configuration or data store amplifies the impact because maliciously crafted documents can persist and affect multiple requests or tenants.

Mongodb-Specific Remediation in Grape — concrete code fixes

To remediate open redirect risks when using MongoDB with Grape, validate and canonicalize any redirect target before using it in a response Location header. Prefer server-side mapping of redirect keys to canonical URLs stored in MongoDB, and avoid directly using user-supplied values in Location headers. Below are concrete examples that demonstrate safe patterns.

Example 1: Whitelisted redirect keys

Store allowed redirect URIs or keys in MongoDB and resolve them on the server. Do not concatenate user input directly into the Location value.

require 'grape'
require 'mongo'

client = Mongo::Client.new(['127.0.0.1:27017'], database: 'myapp')

class RedirectAPI < Grape::API
  helpers do
    def canonical_redirect_key(key)
      # Only allow known keys mapped to safe URIs in MongoDB
      mapping = client[:redirect_mappings].find(key: key).first
      mapping&.fetch('uri', nil)
    end
  end

  get '/complete' do
    key = params[:redirect_key]
    uri = canonical_redirect_key(key)
    if uri && uri.start_with?('https://trusted.example.com/')
      redirect uri, 302
    else
      error!('Invalid redirect target', 400)
    end
  end
end

Example 2: Server-side resolved callback URLs

When clients register a callback, store the full URL in MongoDB after strict validation. On completion, use the stored value rather than re-accepting user input.

require 'grape'
require 'mongo'
require 'uri'

client = Mongo::Client.new(['127.0.0.1:27017'], database: 'myapp')

def safe_redirect_uri(input_url)
  uri = URI.parse(input_url)
  # Enforce HTTPS and a specific host
  return nil unless uri.is_a?(URI::HTTP) || uri.is_a?(URI::HTTPS)
  return nil unless uri.host == 'app.example.com'
  # Ensure path is safe and does not contain unexpected redirects
  uri.path = '/auth/callback' if uri.path.empty?
  uri.to_s
rescue URI::InvalidURIError
  nil
end

class OAuthAPI < Grape::API
  post '/register_callback' do
    raw = params[:uri]
    safe = safe_redirect_uri(raw)
    unless safe
      error!('Invalid callback URI', 400)
    end
    client[:callbacks].insert_one(owner_id: current_user.id, uri: safe)
    { status: 'registered' }
  end

  get '/finish' do
  doc = client[:callbacks].find(owner_id: current_user.id).first
  redirect doc['uri'], 302 if doc
end

Example 3: Reject non-whitelisted hosts

When constructing redirects from MongoDB-stored values, enforce a strict host allowlist and avoid trusting the stored protocol-relative or fully-qualified URLs without checks.

require 'grape'
require 'mongo'

client = Mongo::Client.new(['127.0.0.1:27017'], database: 'myapp')

class SafeRedirectEndpoint < Grape::API
  ALLOWED_HOSTS = %w[app.example.com ui.example.com]

  get '/external' do
    key = params[:key]
    entry = client[:redirects].find(key: key).first
    target = entry&.fetch('url', nil)
    if target
      uri = URI.parse(target)
      if ALLOWED_HOSTS.include?(uri.host)
        redirect target, 302
      else
        error!('Redirect host not allowed', 403)
      end
    else
      error!('Not found', 404)
    end
  end
end

Frequently Asked Questions

Can an attacker modify MongoDB documents to change redirect targets?
Yes, if an attacker can modify documents via IDOR, BOLA, or compromised credentials, they can inject malicious redirect URIs. Always validate and canonicalize stored redirect values and prefer server-side mappings instead of trusting stored URLs directly.
Is a client-side redirect safer than a server-side redirect in this context?
No. Whether the redirect is issued by the server (Location header) or by client-side JavaScript, if the target originates from MongoDB without strict validation, an attacker-controlled document can lead to phishing or malware delivery. Validate and restrict allowed targets regardless of where the redirect is executed.