Server Side Template Injection in Rocket with Basic Auth
Server Side Template Injection in Rocket with Basic Auth — how this specific combination creates or exposes the vulnerability
Server Side Template Injection (SSTI) in the Rocket web framework occurs when an attacker can control a template input that is rendered by a server-side engine such as Askama or Tera, and that input is influenced by authentication material like Basic Auth credentials. When Basic Auth is used, the username and password are typically decoded from the Authorization header and may be passed into request handling logic or templates, either directly or via downstream data structures. If these values are interpolated into a template without proper validation or escaping, an attacker can inject template logic that leads to arbitrary code execution or information disclosure.
In Rocket, routes often deserialize request guards such as BasicAuth from the header, producing a struct containing the provided username and password. If these fields are forwarded to a templating context—such as passing the auth struct or its fields into a context map for rendering—an SSTI vector emerges. For example, an attacker who knows the template engine’s syntax (e.g., Tera’s {{ ... }} syntax) can craft a username like {{ 7*7 }} or more dangerous payloads that execute filesystem or network calls when the template is rendered. Because Basic Auth credentials are often logged or echoed for debugging, the injection may also aid in reconnaissance. The combination is particularly dangerous when the application trusts user-controlled data derived from authenticated headers and passes it into templates without strict allowlisting or escaping.
Consider a Rocket handler that decodes Basic Auth and builds a context for Tera:
use rocket::http::Status;
use rocket::request::FromRequest;
use rocket::request::Request;
use rocket::outcome::Outcome;
use rocket_dyn_templates::{context, Template};
#[derive(Debug)]
struct BasicAuth {
username: String,
password: String,
}
#[rocket::async_trait]
impl<'_> rocket::request::FromRequest<'_, ()> for BasicAuth {
type Error = ();
async fn from_request(req: &Request<'>) -> Outcome<Self, Self::Error> {
let auth_header = req.headers().get_one("Authorization");
if let Some(header) = auth_header {
if header.starts_with("Basic ") {
let encoded = header.trim_start_matches("Basic ");
if let Ok(decoded) = base64::decode(encoded) {
if let Ok(credentials) = String::from_utf8(decoded) {
let parts: Vec<&str> = credentials.splitn(2, ':').collect();
if parts.len() == 2 {
return Outcome::Success(BasicAuth {
username: parts[0].to_string(),
password: parts[1].to_string(),
});
}
}
}
}
}
Outcome::Forward(())
}
}
#[get("/profile")]
async fn profile(auth: BasicAuth, tera: &Tera) -> Result<Template, Status> {
// UNSAFE: directly using auth fields in template context
let ctx = context! {
username => auth.username,
password => auth.password,
};
Ok(Template::render("profile", &ctx))
}
If the profile.html.tera template includes user-controlled content without escaping, an SSTI payload in the username can execute code. Rocket’s runtime does not inherently sanitize inputs that reach templates; developers must ensure that only trusted, validated data enters the rendering context. MiddleBrick can detect such risky patterns by correlating OpenAPI/Swagger spec definitions (including security schemes like Basic Auth) with runtime behavior, highlighting untrusted data flows into template rendering.
Basic Auth-Specific Remediation in Rocket — concrete code fixes
To mitigate SSTI when using Basic Auth in Rocket, ensure that authentication-derived data never reaches the template context, or that it is sanitized and strictly limited. The safest approach is to avoid passing credentials into templates entirely. If metadata derived from credentials is needed, use allowlisted, non-sensitive values and encode output contextually based on the template language.
Refactor the handler to exclude auth fields from the template context. Instead, pass only non-sensitive, validated data:
use rocket_dyn_templates::{context, Template};
#[get("/profile")]
async fn profile_safe(auth: BasicAuth, tera: &Tera) -> Result<Template, Status> {
// SAFE: only non-sensitive, validated data in context
let ctx = context! {
username_display => sanitize_username(&auth.username),
};
Ok(Template::render("profile", &ctx))
}
fn sanitize_username(username: &str) -> String {
// Allowlist alphanumeric and limited symbols; truncate or hash as appropriate
username.chars().filter(|c| c.is_alphanumeric() || *c == '_' || *c == '-').take(64).collect()
}
When you must use templating features based on auth-derived values, enforce strict escaping. For Tera, mark variables as safe only when you fully trust the content; prefer using filters for encoding:
{{ username | e }} {# HTML-escape in Tera #}
Additionally, validate and constrain Basic Auth credentials at the route level before they are deserialized. Use Rocket’s request guards to reject malformed or unexpected inputs, and log authentication attempts without exposing credentials in logs or templates. MiddleBrick’s scans can highlight routes where authentication data is used in rendering contexts, supporting compliance mappings to OWASP API Top 10 and other frameworks.
Tooling integrations can streamline remediation: the middleBrick CLI (middlebrick scan <url>) can be run locally to validate changes, the GitHub Action can enforce risk thresholds in CI/CD, and the MCP Server can provide inline guidance in AI coding assistants. The Dashboard enables tracking of scores and findings over time, helping ensure that fixes do not reintroduce vulnerabilities.