Open Redirect in Grape with Firestore
Open Redirect in Grape with Firestore — how this specific combination creates or exposes the vulnerability
An open redirect in a Grape API that uses Firestore typically occurs when an endpoint accepts a user-controlled URL or host parameter and then redirects the client to that value without strict validation. If the endpoint also reads or writes data in Firestore, an attacker can combine a malicious redirect with a legitimate-looking Firestore-based flow to phish users or abuse trust. For example, a client-side application might call /auth/callback?next_url=https://example.com/dashboard and the server uses a Firestore document to decide which UI to render or which deep link to return. If next_url is used directly in a redirect without verifying it against an allowlist or origin check, the Firestore data and the redirect logic together create an open redirect surface.
In a Grape API, this often manifests as a route that retrieves a redirect target from Firestore (e.g., campaign or feature-flag documents that include a URL field) and then calls redirect. If the stored URL is ever compromised or the API trusts client-supplied keys to select which Firestore document to use, an attacker can cause the API to redirect victims to arbitrary destinations. Because the API presents as a trusted service (hosting a legitimate domain and using Firestore for configuration), users and security tools may not immediately recognize the redirect as malicious. This is especially risky when the endpoint is unauthenticated or uses weak access controls, as it lowers the bar for exploitation.
An example vulnerable pattern in Grape:
class Redirects < Grape::API
format :json
helpers do
def firestore_doc(collection, id)
# pseudo Firestore client call
FirestoreService.get(collection, id)
end
end
get '/landing' do
doc = firestore_doc('landing_pages', params[:page_id])
# Risky: no validation of doc['url'] before redirect
redirect doc['url'], status: 302
end
end
Here, page_id selects a Firestore document whose url field is used directly in redirect. If an attacker can control page_id to point to a malicious document, they can cause the API to redirect users anywhere. Even if page_id is restricted, a stored XSS or misconfigured Firestore permissions could let an attacker modify the URL in the database, turning a trusted redirect into a phishing vector.
Because middleBrick tests unauthenticated attack surfaces and scans 12 security checks in parallel including BOLA/IDOR, Input Validation, and Property Authorization, it can surface such redirect risks when a redirect location depends on Firestore data. Its findings will include severity, a description, and remediation guidance, and the scan integrates with the Dashboard and CLI so teams can track and manage the issue.
Firestore-Specific Remediation in Grape
Remediation focuses on strict validation and separation of data from redirect targets. Never use raw Firestore fields as redirect URLs without validation. Instead, use allowlists, canonical mappings, or store only safe paths that your server resolves to known destinations. If you must store URLs in Firestore, validate them against a strict allowlist of hosts and enforce same-origin redirects for sensitive flows.
Below are concrete, Firestore-aware fixes for Grape endpoints.
1. Use canonical path mapping instead of raw URLs
Store only short, controlled keys in Firestore and map them to fixed destinations in code. This eliminates the ability to inject arbitrary redirect targets.
class Redirects < Grape::API
format :json
ALLOWED_PAGES = {
'dashboard' => 'https://app.example.com/dashboard',
'settings' => 'https://app.example.com/settings',
'help' => 'https://docs.example.com/help'
}.freeze
get '/landing' do
key = params[:page_key]
url = ALLOWED_PAGES[key]
unless url
error!({ error: 'Invalid page key' }, 400)
end
redirect url, status: 302
end
end
This approach removes any user-controlled URL from Firestore and from the redirect logic entirely. The Firestore document can still hold metadata, but the redirect target is fixed in the API.
2. Validate and sanitize if you must store URLs in Firestore
If business requirements demand configurable URLs, store them in Firestore but validate strictly at runtime. Use Ruby’s URI library to parse and enforce same-origin or approved domains, and avoid 307/308 redirects for user-supplied values.
require 'uri'
class Redirects < Grape::API
format :json
ALLOWED_HOSTS = %w[app.example.com static.example.com].freeze
helpers do
def safe_redirect_url(candidate)
uri = URI.parse(candidate)
# reject non-HTTP schemes and blank hosts
return nil unless %w[http https].include?(uri.scheme)
return nil unless ALLOWED_HOSTS.include?(uri.host)
# ensure no user-controlled path traversal surprises
uri.path = '/' if uri.path.to_s.empty?
uri.to_s
rescue URI::InvalidURIError
nil
end
end
get '/feature' do
doc = FirestoreService.get('features', params[:feature_id])
url = safe_redirect_url(doc['redirect_url'])
unless url
error!({ error: 'Invalid redirect configuration' }, 400)
end
redirect url, status: 302
end
end
This validates the parsed URL’s scheme and host, mitigating open redirect while still allowing controlled Firestore-driven destinations. It also normalizes the path to avoid path-traversal tricks.
3. Enforce referrer or origin checks for sensitive flows
For endpoints that can be triggered cross-origin, combine server-side validation with referrer/origin checks to reduce abuse even if a URL is mistakenly trusted. This complements but does not replace allowlist validation.
By combining these patterns and using middleBrick’s scans (Dashboard, CLI, or GitHub Action) to detect missing validation and BOLA/IDOR issues, teams can harden Grape APIs that rely on Firestore and avoid introducing open redirects into authentication or configuration flows.