HIGH crlf injectionsinatraruby

Crlf Injection in Sinatra (Ruby)

Crlf Injection in Sinatra with Ruby — 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 (LF, \n) sequence into a header or status-line context. In Sinatra with Ruby, this often arises when user-controlled input is reflected in HTTP response headers without sanitization. Because Sinatra is a lightweight Ruby DSL built on Rack, developers sometimes treat headers as purely strings, inadvertently allowing injection of additional headers or response splitting.

For example, if a route uses headers['X-Redirect'] directly from params and passes it to redirect or sets it via header, an input like example.com\r\nSet-Cookie: session=evil can introduce a second header line. Rack expects headers as a hash, but if you construct raw header strings or use low-level Rack response manipulation, the injected CRLF can cause header injection, cache poisoning, or open the response to response-smuggling-like behaviors in chained proxies.

Ruby’s String handling preserves these characters, so unless you explicitly reject or encode \r and \n, the injected sequence may be interpreted by downstream HTTP components. In Sinatra, common triggers include:

  • Using redirect "http://#{params[:url]}" without validating that params[:url] contains no CRLF.
  • Setting custom headers via header 'X-Value', params[:input] where params[:input] includes \r\n.
  • Streaming or constructing responses manually with Rack response arrays where newlines are not escaped.

Because Sinatra encourages concise route definitions, developers may overlook sanitization, especially when headers are built dynamically. The framework does not automatically neutralize CRLF in user input, so the burden is on the developer to treat header context as a strict boundary: once user data crosses into header values or status codes, it must be validated and encoded.

An attacker might probe such endpoints using inputs like \r\nSet-Cookie: auth=1 or \r\nLocation: https://evil.com to test for response splitting. In environments with multiple proxies, a successful injection could allow an attacker to inject arbitrary headers or split the response, potentially misleading downstream caches or clients. This maps to the broader OWASP API Top 10 category 'Security Misconfiguration' and can intersect with smuggling-related weaknesses if proxies interpret the injected sequences inconsistently.

Ruby-Specific Remediation in Sinatra — concrete code fixes

Defensive validation and safe abstractions are the primary mitigations. In Ruby, prefer using symbols or symbols for header keys and rely on Rack’s hash-based header handling rather than string concatenation. Below are concrete, Sinatra-specific patterns to eliminate CRLF risk.

1. Validate and sanitize header inputs

Never pass raw user input into header values. Use a denylist or allowlist to reject control characters. For example:

# Reject CRLF in any user-controlled header value
def safe_header(value)
  return nil if value.to_s.include?("\r") || value.to_s.include?("\n")
  value
end

get '/set-header' do
  input = params['input']
  safe = safe_header(input)
  if safe
    header 'X-Custom', safe
  else
    status 400
    { error: 'Invalid header value' }.to_json
  end
end

2. Use symbols for header keys and avoid string interpolation in redirects

When redirecting, validate the target URL to ensure it does not contain CRLF. Prefer URI parsing to enforce a safe schema/host structure:

require 'uri'

get '/redirect' do
  url = params['url']
  begin
    uri = URI.parse(url)
    if uri.host.nil? || url.include?("\r") || url.include?("\n")
      status 400
      { error: 'Invalid redirect URL' }.to_json
    else
      redirect uri.to_s
    end
  rescue URI::InvalidURIError
    status 400
    { error: 'Invalid URL' }.to_json
  end
end

3. Prefer hash-based header setting over raw strings

Sinatra’s headers helper accepts a hash, which Rack safely serializes. Avoid constructing header lines manually:

# Safe: hash-based headers
get '/profile' do
  headers 'Content-Type' => 'application/json',
          'X-Request-ID' => SecureRandom.uuid
  { user: 'alice' }.to_json
end

# Unsafe: string-based header construction (do not do this)
# get '/unsafe' do
#   header_line = "X-Request-ID: #{params['id']}\r\nX-Extra: injected"
#   headers header_line  # Risk if params['id'] contains CRLF
# end

4. Leverage middleware or filters for global sanitization

Use a before filter to scrub headers across all routes:

before do
  request.headers.each do |key, value|
    if value.to_s.include?("\r") || value.to_s.include?("\n")
      halt 400, { error: 'Invalid header value' }.to_json
    end
  end
end

5. Escape output when reflecting user input in responses

If you must include user input in a response body, ensure it does not contain literal CRLF that a downstream proxy might misinterpret. Use encoding or simple replacement:

get '/echo' do
  content_type 'text/plain'
  input = params['text'] || ''
  input.gsub(/[\r\n]/, '')  # Remove CR/LF to prevent smuggling in plain text
end

These patterns align with middleBrick’s checks for Input Validation and can complement scans that flag header-injection risks. By validating inputs at the boundary and using Ruby’s hash-based headers, you reduce the chance of response splitting without relying on ad-hoc string manipulation.

Frequently Asked Questions

Can CRLF Injection in Sinatra allow response smuggling even if the app doesn’t use redirects?
Yes. If user input is reflected in custom headers or status codes and contains \r\n, it can split the response. Downstream proxies or caches may interpret injected headers independently, leading to smuggling-like effects even without redirects.
Does middleBrick detect CRLF Injection in Sinatra endpoints during scans?
Yes. middleBrick runs an Input Validation check that tests for CRLF and other control characters in reflected headers and status contexts. Findings include severity, details, and remediation guidance mapped to frameworks such as OWASP API Top 10.