Crlf Injection in Rocket
How Crlf Injection Manifests in Rocket
CRLF injection in Rocket manifests through improper handling of newline characters in HTTP headers and response manipulation. In Rocket applications, this vulnerability typically appears when user input is directly incorporated into HTTP headers without proper sanitization.
The most common vectors include:
- Header injection via query parameters that become part of response headers
- Redirect manipulation where user input affects Location headers
- Cookie injection through unsanitized header values
- Response splitting attacks where newline characters create additional HTTP responses
Rocket's type-safe routing system doesn't inherently prevent CRLF injection—it's still possible when developers use the Header or Response APIs incorrectly. For example:
use rocket::http::Header;
#[get("/unsafe-header?")]
fn unsafe_header(user_input: String) -> String {
// Dangerous: user_input could contain newline characters
let malicious_header = Header::new("X-User-Input", user_input);
// ... response construction
"OK".to_string()
}
If user_input contains \r\n sequences, an attacker could inject arbitrary headers or even split responses. Another common pattern in Rocket involves dynamic redirects:
#[get("/redirect?")]
fn redirect(url: String) -> Redirect {
// Vulnerable if url contains newline characters
Redirect::to(url)
}
An attacker could craft a URL like /redirect?url=http://evil.com%0D%0AX-Injected: value, causing Rocket to generate a response with injected headers. The vulnerability becomes more severe when combined with response splitting, where an attacker can create multiple HTTP responses from a single request, potentially bypassing security controls or manipulating client behavior.
Rocket-Specific Detection
Detecting CRLF injection in Rocket applications requires both static analysis and runtime scanning. Static analysis involves examining route handlers that accept user input and checking if that input flows into header construction or response generation.
Key detection patterns in Rocket code:
// Look for these patterns:
let header = Header::new("Name", user_input); // UNSAFE if user_input unvalidated
let response = Response::build().raw_header("Name", user_input); // UNSAFE
let redirect = Redirect::to(user_input); // UNSAFE if user_input contains newlines
middleBrick's scanning approach for Rocket applications includes:
- Automated testing of all GET endpoints with newline character payloads (%0D%0A, %0D%0A%0D%0A)
- Header injection attempts on endpoints accepting query parameters
- Response splitting tests by sending crafted payloads to vulnerable endpoints
- Analysis of OpenAPI specifications to identify risky parameter-to-header mappings
- LLM security checks for AI endpoints that might process or generate header-like content
For local testing, you can manually test your Rocket application:
curl -v "http://localhost:8000/redirect?url=http://example.com%0D%0AX-Test: injected"
Look in the response headers for the injected X-Test header. If it appears, your application is vulnerable. middleBrick automates this testing across all endpoints, providing a security score and detailed findings without requiring you to manually craft attack payloads.
Rocket-Specific Remediation
Rocket provides several mechanisms to prevent CRLF injection. The most effective approach is input validation and sanitization before using user input in headers or redirects.
For query parameters that become headers, use Rocket's built-in validation:
use rocket::http::uri::Uri;
use rocket::http::uri::Origin;
#[get("/safe-header?")]
fn safe_header(user_input: String) -> String {
// Sanitize: remove any newline characters
let sanitized = user_input.replace(["\r", "\n"], "");
// Safe: sanitized input used in header
let header = Header::new("X-User-Input", sanitized);
// ... include header in response
"OK".to_string()
}
For redirects, validate the URL before using it:
use rocket::http::uri::Uri;
use rocket::http::uri::Origin;
use rocket::response::Redirect;
#[get("/safe-redirect?")]
fn safe_redirect(url: String) -> Result {
// Validate URL format
if let Ok(uri) = Origin::parse(url) {
// Check for newline characters
if url.contains(["\r", "\n"]) {
return Err("Invalid URL");
}
Ok(Redirect::to(uri))
} else {
Err("Invalid URL format")
}
}
Rocket's Uri type provides additional safety for redirect targets:
use rocket::http::uri::Uri;
use rocket::http::uri::Origin;
use rocket::response::Redirect;
#[get("/redirect-to-safe?")]
fn redirect_to_safe(url: &RawStr) -> Result {
// Parse and validate the URL
match Uri::parse(url, Origin::parse) {
Ok(uri) => {
// Additional check for malicious content
if uri.path().contains(["\r", "\n"]) {
return Err("Malicious content detected");
}
Ok(Redirect::to(uri))
}
Err(_) => Err("Invalid URL")
}
}
For comprehensive protection, implement a middleware or request guard that automatically sanitizes headers:
use rocket::request::{FromRequest, Request};
use rocket::outcome::Outcome;
use rocket::http::Status;
struct SanitizedHeaders;
#[rocket::async_trait]
impl<'r> FromRequest<'r> for SanitizedHeaders {
type Error = ();
async fn from_request(request: &'r Request<'_>) -> Outcome {
// Check for malicious headers in the request
for header in request.headers() {
if header.name().contains(["\r", "\n"]) ||
header.value().contains(["\r", "\n"]) {
return Outcome::Failure((Status::BadRequest, ()));
}
}
Outcome::Success(SanitizedHeaders)
}
}
// Use in routes
#[get("/protected?")]
fn protected(param: String, _guard: SanitizedHeaders) -> String {
// Processing continues only if headers are clean
format!("Processed: {}", param)
}
middleBrick's CLI tool can help verify your remediation:
npx middlebrick scan http://localhost:8000
This scans all endpoints for CRLF injection vulnerabilities, providing a security score and specific findings for each endpoint tested.