Crlf Injection in Grape with Cockroachdb
Crlf Injection in Grape with Cockroachdb — 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, causing the server to prematurely terminate the current line and inject additional lines. In a Grape API backed by Cockroachdb, this typically arises when user-controlled input is reflected into HTTP headers or SQL comments without proper sanitization.
Consider a Grape endpoint that builds a custom header value using a request parameter, and then uses that value in a Cockroachdb query:
class V1 < Grape::API
format :json
helpers do
def db_query_for(user_token)
DB["SELECT * FROM users WHERE token = $1", user_token].first
end
end
get '/profile' do
token = params[:token]
# Unsafe: token used directly in a header-like context or logged value
header['X-User-Token'] = token
db_query_for(token)
end
end
If token contains a sequence like \r\nX-Injected: yes, and the logging or header layer treats the value as line-based text, the injected sequence can split the header stream. In Cockroachdb, while SQL strings are parameterized and not directly vulnerable to CRLF injection, the surrounding application layer is: the injected sequence can break header parsing, enable response splitting, or manipulate logging formats that later feed into audit trails or monitoring tied to Cockroachdb queries.
The risk is compounded when Grape responses are proxied through a gateway that buffers lines, or when Cockroachdb logs capture request metadata that include header-like fields. An attacker may achieve:
- HTTP response splitting, leading to cache poisoning or XSS in downstream clients.
- Log injection that obscures real queries or enables log-based data exfiltration if logs are correlated with Cockroachdb statement identifiers.
- Header smuggling when requests are chained through load balancers that rely on header boundaries.
Because Cockroachdb is often used in distributed systems where request IDs and trace headers are logged, a CRLF in a user-controlled token can forge additional pseudo-headers in those logs, complicating forensic analysis. The vulnerability is not in Cockroachdb itself but in how Grape constructs and transmits data around it.
Cockroachdb-Specific Remediation in Grape — concrete code fixes
Remediation focuses on strict input validation, safe header construction, and ensuring that any value derived from user input is sanitized before being used in line-based protocols. Below are concrete patterns for a Grape API interacting with Cockroachdb.
1. Validate and sanitize header values
Never assign raw user input to HTTP headers. Use a whitelist or a sanitization function that strips CR and LF characters:
class V1 < Grape::API
format :json
helpers do
def safe_header_value(input)
# Remove CR and LF characters to prevent header injection
input.to_s.gsub(/[\r\n]/, '')
end
def db_query_for(user_token)
DB["SELECT * FROM users WHERE token = $1", user_token].first
end
end
get '/profile' do
token = params[:token]
# Safe: sanitize before using in headers
header['X-User-Token'] = safe_header_value(token)
db_query_for(token)
end
end
2. Use parameterized queries and avoid string interpolation
With Cockroachdb, always use placeholders ($1, $2) and never concatenate user input into SQL strings. This prevents SQL injection and ensures line-based attacks cannot alter query structure:
class V1 < Grape::API
format :json
helpers do
def db_safe_user(token)
# Parameterized query prevents injection at the SQL layer
DB["SELECT id, email FROM users WHERE token = $1 LIMIT 1", token].first
end
end
get '/user' do
token = params[:token]
# Reject tokens containing control characters early
halt 400, { error: 'invalid_token' } if token.to_s.match?(/[\r\n]/)
user = db_safe_user(token)
error!('Not found', 404) unless user
user
end
end
3. Enforce strict input constraints and logging hygiene
Add request-level guards and ensure logs do not treat user input as line-oriented. When integrating with Cockroachdb’s logging or observability, avoid echoing raw headers into structured log lines that could be parsed as multi-line:
class V1 < Grape::API
format :json
before do
# Reject early if token contains CR/LF
halt 400, { error: 'invalid_token' } if params[:token].to_s.match?(/\r|\n/)
end
helpers do
def db_query(token)
DB["SELECT * FROM users WHERE token = $1", token].first
end
end
get '/account' do
token = params[:token]
user = db_query(token)
# Safe logging: avoid embedding raw token in lines that may be parsed by Cockroachdb-compatible log parsers
Rack::Logger.new.info("user_lookup id=#{user&.fetch('id', 'unknown')}")
user
end
end
These steps ensure that CRLF injection vectors are closed at the Grape layer while maintaining safe, parameterized interactions with Cockroachdb. The key is to treat any user-controlled data as potentially line-oriented and to enforce boundaries before data reaches headers, logs, or SQL strings.