Container Escape in Rocket with Basic Auth
Container Escape in Rocket with Basic Auth — how this specific combination creates or exposes the vulnerability
A container escape occurs when a process breaks out of its isolated environment to affect the host or other containers. In the Rocket web framework, using HTTP Basic Auth can inadvertently support this scenario when authentication is not strictly enforced for administrative or introspection endpoints, or when authentication data is mishandled in downstream processing. Rocket’s routing and request guards integrate with the managed state such that, if an endpoint that should be protected is accidentally left unguarded, an attacker who discovers it can make authenticated requests using leaked or guessed credentials and then probe for host-level interactions.
When Basic Auth is implemented but not uniformly applied—especially across routes that expose configuration, debugging, or metrics—this inconsistency becomes an avenue for container escape via trusted internal interactions. For example, an endpoint that returns environment variables or runtime configuration might be intended for authenticated admin use, but if the guard is missing or conditionally bypassed, an attacker with valid Basic Auth credentials can read sensitive host-level data that should remain container-internal. Similarly, if Basic Auth credentials are parsed and forwarded to other services or scripts within the container without strict validation, an attacker might inject newline or shell metacharacters to trigger command injection or header smuggling that leads to interaction with the host filesystem or process space.
Another angle involves unauthenticated LLM or automation features that may be inadvertently exposed. If a Rocket service hosts an endpoint that triggers automated tasks or integrates with an LLM service and relies solely on Basic Auth for access, misconfigured CORS or route guards can allow an authenticated session to be abused to run arbitrary code on the host via crafted inputs that escape the container’s expected execution context. This is not a flaw in Basic Auth itself, but a consequence of how the framework enforces—and fails to enforce—authorization across all routes and how credentials are handled in logging, error messages, or forwarded requests. Properly scoped guards and strict input validation are essential to prevent authenticated sessions from becoming a pathway for container escape.
Basic Auth-Specific Remediation in Rocket — concrete code fixes
Remediation centers on consistent enforcement of authentication guards, careful handling of credentials, and avoiding any route that exposes host-level details without strict access control. Below are concrete code examples in Rocket that demonstrate secure Basic Auth usage and how to avoid common pitfalls.
1. Enforce authentication on all sensitive routes
Ensure that every route that can affect host or container state is protected by a fairing or a request guard that validates credentials on every request. Do not rely on route-level guards alone; apply a global catcher or fairing to reject unauthenticated access.
#[macro_use] extern crate rocket;
use rocket::http::Status;
use rocket::request::{self, FromRequest, Request};
use rocket::Outcome;
struct Authenticated;
#[rocket::async_trait]
impl<'r> FromRequest<'r> for Authenticated {
type Error = ();
async fn from_request(request: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
let headers = request.headers();
let auth_header = match headers.get_one("authorization") {
Some(h) => h,
None => return Outcome::Failure((Status::Unauthorized, ())),
};
if auth_header.starts_with("Basic ") {
// Perform validation of credentials (e.g., decode and compare)
let token = &auth_header[6..];
if validate_basic_token(token) {
return Outcome::Success(Authenticated);
}
}
Outcome::Failure((Status::Unauthorized, ()))
}
}
fn validate_basic_token(token: &str) -> bool {
// Replace with secure credential lookup; this is a simplified example
token == "dXNlcjpwYXNz" // "user:pass" base64
}
#[get("/admin/config")]
async fn admin_config(_auth: Authenticated) -> String {
// Safe to expose internal config only when authenticated
"{"debug": false, "version": "1.0"}".to_string()
}
#[launch]
fn rocket() -> _ {
rocket::build().mount("/", routes![admin_config])
}
2. Avoid logging or echoing credentials
Ensure that Basic Auth credentials are not included in logs, error messages, or responses. Rocket’s request guards should extract credentials only for validation and immediately discard them rather than storing or forwarding them.
// Do NOT do this:
fn unsafe_handler(headers: &HeaderMap) -> String {
let auth = headers.get("authorization").unwrap().to_str().unwrap();
info!("Incoming auth header: {}", auth); // Risk of leaking credentials
// process...
}
// Do this instead:
fn safe_handler(_auth: Authenticated) -> String {
// Use guard result, do not handle raw header
"OK".to_string()
}
3. Validate and sanitize any input derived from authenticated requests
If authenticated endpoints forward data to other services or scripts, validate and sanitize all inputs to prevent injection that could lead to container escape. Never construct shell commands from user-supplied headers or parameters, even when the request is authenticated.
#[post("/run", data = "<input")]
async fn run_command(_auth: Authenticated, input: String) -> Result<String, Status> {
if input.contains(';') || input.contains('&') || input.contains('|') {
return Err(Status::BadRequest);
}
// Safe processing without shell invocation
Ok(format!("Processed: {}", input))
}
4. Use structured data instead of forwarding credentials
When integrating with other services, pass only necessary opaque tokens or session identifiers rather than the full Basic Auth header. This limits the blast radius if a downstream component is compromised.
// Extract user identity safely and issue a scoped token
fn issue_scoped_token(validated_user: &str) -> String {
// Return a short-lived JWT or session ID, not the Basic Auth string
format!("scoped_{}", validated_user)
}