Open Redirect in Grape with Mutual Tls
Open Redirect in Grape with Mutual Tls — how this specific combination creates or exposes the vulnerability
An open redirect in a Grape API occurs when an attacker can control the redirect target, typically via a URL parameter, causing the server to forward the client to an arbitrary location. Mutual Transport Layer Security (Mutual TLS) authenticates both client and server using certificates, which secures the channel and verifies identities. However, Mutual TLS does not validate the semantics of application-level redirects. If a Grape endpoint uses a user-supplied parameter to construct a redirect (e.g., redirecting after login or to an external link) without strict allowlisting, the encrypted and authenticated tunnel provided by Mutual TLS does not prevent the malicious redirect itself.
Consider a Grape resource that accepts a next query parameter and redirects to it after successful authentication. With Mutual TLS enabled, the client presents a valid certificate, the server validates it, and the request proceeds. The encrypted connection terminates at the server, and from the server’s perspective, the redirect is a legitimate internal action. Because Mutual TLS does not restrict where the server may send the client afterward, an attacker who controls the next parameter can supply a malicious external URL, and the server will issue a 302 to that location. This creates an open redirect that leverages Mutual TLS for authentication but does not mitigate business logic flaws in routing.
Moreover, if the Grape service also acts as a reverse proxy or gateway that terminates Mutual TLS and forwards requests internally, misconfigured trust boundaries may expose redirect logic to internal services. An attacker who bypasses or compromises client certificate validation (for example, through a misissued certificate or a vulnerable client configuration) could directly invoke the redirect endpoint. Even with valid client certs, the server must still validate the target against an allowlist; otherwise, the combination of Mutual TLS and unchecked redirects leads to phishing-prone behavior where authenticated users are directed to malicious sites.
Mutual Tls-Specific Remediation in Grape — concrete code fixes
To remediate open redirects in Grape when using Mutual TLS, you must enforce allowlisted redirect targets and avoid reflecting user input directly into Location headers. Below are concrete examples demonstrating secure practices alongside insecure patterns.
Insecure Example (Do Not Use)
require 'grape'
class InsecureAPI < Grape::API
format :json
get '/redirect' do
# Dangerous: directly using user input for redirect
next_url = params[:next]
redirect next_url, 302
end
end
This endpoint reflects the next parameter into a redirect, enabling open redirection even when Mutual TLS is enforced for client authentication.
Secure Example with Allowlist
require 'grape'
class SecureAPI < Grape::API
format :json
ALLOWED_HOSTS = ['app.example.com', 'dashboard.example.com'].freeze
helpers do
def safe_redirect_url(input)
uri = URI.parse(input)
# Ensure scheme is HTTPS and host is in allowlist
if uri.https? && ALLOWED_HOSTS.include?(uri.host)
uri.to_s
else
nil
end
rescue URI::InvalidURIError
nil
end
end
get '/redirect' do
next_url = params[:next]
target = safe_redirect_url(next_url)
if target
redirect target, 303
else
error!('Invalid redirect target', 400)
end
end
end
This approach parses the user input as a URI, enforces HTTPS, and checks the host against an allowlist before redirecting. It prevents open redirects regardless of Mutual TLS being in place.
Mutual TLS Client Setup Example (for reference)
require 'net/http'
require 'openssl'
ctx = OpenSSL::SSL::SSLContext.new
ctx.key = OpenSSL::PKey.read(File.read('client.key'))
ctx.cert = OpenSSL::X509::Certificate.new(File.read('client.crt'))
ctx.ca_file = 'ca.pem'
ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
http = Net::HTTP.new('api.example.com', 443)
http.use_ssl = true
http.ssl_context = ctx
request = Net::HTTP::Get.new('/redirect?next=https://app.example.com/dashboard')
response = http.request(request)
puts response.code, response['location']
This client example shows how Mutual TLS is configured with certificate and CA verification. While this secures the transport, the server-side Grape application must still validate redirect targets independently.
Additional Hardening
- Use 303 See Other for redirects after POST/PUT to prevent certain types of request smuggling.
- Set a strict Content-Security-Policy header to mitigate any potential client-side impact if a redirect is inadvertently allowed.
- Log suspicious redirect attempts for monitoring and anomaly detection.