Log Injection in Actix with Jwt Tokens
Log Injection in Actix with Jwt Tokens — how this specific combination creates or exposes the vulnerability
Log injection occurs when untrusted input is written directly into application logs without validation or sanitization. In Actix applications that rely on JWT tokens for authentication, several specific interactions can turn log output into an attack surface.
When an Actix service validates a JWT, it typically decodes the token, verifies its signature, and extracts claims such as subject, roles, or session identifiers. If any part of this flow logs the raw token, a subset of claims, or error details related to token parsing, an attacker can manipulate the content of the token to inject newline characters or structured payloads. For example, an attacker might supply a token with embedded newline characters in claims like name or jti. When the service logs the claim values, the injected newline causes the log entry to be split, potentially hiding malicious entries or forging log context.
Additionally, Actix middleware that logs request metadata alongside JWT-derived user identifiers can be abused. If the token’s sub or a custom claim includes characters such as carriage returns or control sequences, and those values are concatenated into log messages without escaping, the resulting log lines may appear to originate from a different user or session. This can complicate forensic analysis and allow an attacker to obscure which identity was used in a given request.
Another vector involves error handling during JWT verification. When an invalid token is received, an Actix handler may log the token or specific claim values to aid debugging. If the token contains maliciously crafted data, such as oversized strings or line breaks, the logged output can be polluted. In distributed setups where logs are aggregated centrally, polluted log lines can break parsing, obscure alerts, or trigger injection in log visualization tools that interpret newline or structured delimiters.
Because JWTs often contain user context used for authorization decisions, log injection paired with JWT handling can amplify risks. An attacker might not only pollute logs but also influence how automated systems interpret events, especially when logs are ingested by SIEMs that rely on line-based parsing. The combination of a widely used authentication mechanism like JWT and insufficient input handling around log creation creates a subtle but impactful channel for abuse.
Jwt Tokens-Specific Remediation in Actix — concrete code fixes
Remediation focuses on preventing untrusted data from being written into logs and ensuring JWT handling logic is resilient to injection attempts. Below are concrete Actix patterns and code examples that address log injection risks when working with JWT tokens.
First, avoid logging raw tokens or unescaped claim values. Instead, log only necessary metadata and sanitize any user-controlled content. Use structured logging with dedicated fields rather than string concatenation to retain queryability without risking injection.
use actix_web::{web, HttpRequest, HttpResponse};
use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation};
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
struct Claims {
sub: String,
name: String,
jti: String,
}
async fn handle_request(req: HttpRequest) -> HttpResponse {
let token = match req.headers().get("Authorization") {
Some(h) => h.to_str().unwrap_or("").trim_start_matches("Bearer "),
None => return HttpResponse::Unauthorized().finish(),
};
// Do NOT log the raw token
// log::info!("Token: {}", token);
let validation = Validation::new(Algorithm::HS256);
let key = DecodingKey::from_secret(b"secret");
match decode::(token, &key, &validation) {
Ok(token_data) => {
// Sanitize claim values before logging: replace newlines and control chars
let safe_name = sanitize_log_value(&token_data.claims.name);
let safe_sub = sanitize_log_value(&token_data.claims.sub);
log::info!("user_sub={} user_name={}", safe_sub, safe_name);
HttpResponse::Ok().finish()
}
Err(e) => {
// Log error without including the token
log::warn!("jwt_error: {}", e);
HttpResponse::Unauthorized().finish()
}
}
}
fn sanitize_log_value(value: &str) -> String {
value.chars().filter(|c| !c.is_control()).collect()
}
Second, enforce strict validation of JWT claims to reject tokens with unexpected content. For example, reject tokens where the name or jti contain newline characters before processing or logging.
fn validate_claims(claims: &Claims) -> bool {
// Reject control characters in critical claim fields
claims.name.chars().all(|c| !c.is_control()) &&
claims.sub.chars().all(|c| !c.is_control()) &&
claims.jti.chars().all(|c| !c.is_control())
}
Third, configure your logging framework to output structured formats such as JSON. This reduces the risk of newline injection breaking log parsers. When using the env_logger or similar crates, ensure that log messages are emitted as single-line JSON objects.
// Example of structured, single-line JSON logging
log::info!("{{\"event\":\"auth_success\",\"user_sub\":\"{}\"}}", safe_sub);
Finally, consider applying middleware that normalizes or rejects headers and payloads containing suspicious sequences before they reach JWT handling logic. This reduces the likelihood that malicious input reaches downstream components that generate logs.