Crlf Injection in Grape with Hmac Signatures
Crlf Injection in Grape with Hmac Signatures — how this specific combination creates or exposes the vulnerability
Crlf Injection occurs when an attacker can inject a carriage return (CR, \r) and line feed (\n) sequence into an HTTP header or header-derived value. In a Grape API, this risk can intersect with Hmac Signatures when the signature is computed over a header value that is later reflected into another header without proper sanitization. For example, if a request includes a custom header such as X-Request-ID and that value is used both to compute an Hmac signature and to set a downstream response header, an attacker could inject \r\n into the header to smuggle additional headers or commands.
Consider a Grape endpoint that validates an X-Client-Signature header built over selected request headers. If the server reuses the same header value in a Set-Cookie or Location header without sanitization, the injected \r\n can split the header chain and inject a new header, effectively conducting a response splitting attack. Because the Hmac signature is tied to the original header value, an attacker might attempt to manipulate header ordering or casing to bypass naive canonicalization, while the server’s signature verification may still pass if the canonicalization logic does not explicitly reject or normalize CR and LF characters. This mismatch between signature verification and header handling creates a window where an attacker can exploit Crlf Injection even when signatures are in use.
Another scenario involves the use of the X-Forwarded-Proto or similar headers in signature material. If an attacker can introduce \r\n into these values and the server reflects them into other headers or logs, they can manipulate redirection behavior or leak information. Because Grape applications often rely on Hmac Signatures to ensure request integrity, failing to sanitize and normalize header inputs before including them in the signature scope can lead to situations where the signature validates but the resulting behavior is unsafe. The vulnerability is not in the Hmac algorithm itself, but in how header values are normalized, concatenated, and reused across request processing and response generation.
Hmac Signatures-Specific Remediation in Grape — concrete code fixes
To safely use Hmac Signatures in Grape while preventing Crlf Injection, normalize and strictly validate any header value that contributes to the signature or is reflected into other headers. Reject or percent-encode control characters such as \r and \n in header values before they are used in signature computation or header setting. Below is a complete, realistic example that demonstrates canonicalization, signature verification, and safe header setting in a Grape API.
# Gemfile
gem 'grape'
gem 'openssl' # for OpenSSL::HMAC
# app/api/secure_api.rb
require 'grape'
require 'openssl'
class SecureApi < Grape::API
format :json
helpers do
def allowed_header_names
['X-Request-ID', 'X-Client-Timestamp', 'X-Content-SHA256']
end
def canonicalize_for_signature(request, header_names)
# Normalize header names to a consistent case and exclude unsafe headers
header_names.sort.map do |name|
value = request.get_header("HTTP_#{name.tr('-', '_').upcase}")
# Reject header values containing CR or LF to prevent injection
if value&.match?(/[\r\n]/)
raise Grape::Exceptions::Validation, { message: { header: { name => 'contains invalid characters' } } }
end
"#{name}:#{value.to_s.strip}"
end.join("\n")
end
def compute_hmac(secret, data)
OpenSSL::HMAC.hexdigest('sha256', secret, data)
end
def verify_signature!(request)
secret = ENV.fetch('HMAC_SECRET') { 'development-secret-change-in-production' }
provided = request.get_header('HTTP_X_CLIENT_SIGNATURE')
# Build canonical data from allowed headers only
canonical = canonicalize_for_signature(request, allowed_header_names)
expected = compute_hmac(secret, canonical)
unless Rack::Utils.secure_compare(provided.to_s, expected)
raise Grape::Exceptions::Authentication, 'Invalid signature'
end
end
end
before { verify_signature! }
resource :items do
get do
{ status: 'ok', headers: { 'X-Request-Processed' => 'true' } }
end
end
end
In this example, canonicalize_for_signature normalizes header names, sorts them, and rejects any header values containing CR or LF characters before they are included in the signature scope. By raising a validation error when such characters are detected, the API prevents attackers from smuggling additional headers via Crlf Injection. The verify_signature! helper computes the Hmac over the canonical string and uses Rack::Utils.secure_compare to avoid timing attacks. When setting response headers, ensure you do not directly echo unsanitized input; instead, use fixed values or explicitly validated safe values.
Additionally, prefer using symbols or constants for header names to avoid case-insensitive mismatches, and avoid concatenating raw user input into header values. If you must include user input in headers, apply strict allow-lists and encoding (e.g., Base64) rather than trying to sanitize CR and LF manually. These practices reduce the risk of Crlf Injection while preserving the integrity of Hmac Signatures in Grape APIs.