Log Injection in Actix with Hmac Signatures
Log Injection in Actix with Hmac Signatures — how this specific combination creates or exposes the vulnerability
Log injection occurs when untrusted input is written into application logs without proper sanitization, enabling log forging or log injection attacks that can corrupt log integrity, evade detection, and assist in post-exploitation activities. In Actix web applications, developers sometimes include structured metadata such as Hmac signatures in log entries to provide authenticity guarantees or request tracing. When these Hmac values or related request fields are logged verbatim from user-controlled sources, the combination can inadvertently create a log injection surface.
Consider an Actix handler that computes an Hmac over incoming query parameters or headers and then logs both the parameters and the resulting signature. If the logged parameter values contain newline characters, structured separators, or crafted payloads, an attacker can inject additional log lines or falsify contextual information. For example, a newline (%0A or %0D sequences) in a query parameter can cause the logging framework to emit extra lines that appear to belong to the same logical request. This can break log parsers that rely on line-based ingestion and reduce forensic value. In distributed systems that correlate logs by signature or timestamp, injected content may misleadingly be associated with a valid Hmac context, complicating incident response.
Hmac signatures themselves do not prevent log injection; they ensure integrity between specific fields and the signer’s key. If an application logs the computed Hmac alongside the raw input without validating or escaping the input, the log entry can be manipulated while still appearing consistent with the signature in offline analysis. Attackers may exploit this to obfuscate malicious activity or to trigger log-based monitoring rules that misinterpret injected lines as benign variations. Real-world patterns seen in frameworks like Actix involve concatenating headers and query parameters before signing; if any component includes unescaped user data, the log message becomes malleable.
Specific attack patterns include injecting crafted query strings that contain carriage returns or JSON-like delimiters, causing log parsers to misinterpret the structure of recorded events. In environments where logs are processed by SIEM tools or security dashboards, such injection can lead to missed detections or false negatives. Moreover, if logs contain PII or secrets and are combined with Hmac contexts, injected data might expose sensitive information in otherwise integrity-protected records. Therefore, treating Hmac-signed requests as trusted input sources for logging without sanitization creates a clear path for log injection in Actix-based services.
Hmac Signatures-Specific Remediation in Actix — concrete code fixes
To mitigate log injection when using Hmac signatures in Actix, treat all data destined for logs as untrusted and apply sanitization, structured logging, and separation of concerns. Below are concrete patterns that reduce risk while preserving the integrity properties that Hmac provides.
- Sanitize inputs before logging: strip or escape newline and control characters from any user-supplied values that are included in log messages. For structured formats like JSON, ensure that string fields are properly escaped.
- Log Hmac in a distinct, immutable context: compute the Hmac over canonicalized request data, but log it separately from raw inputs, and avoid concatenating raw user data into the same log line that carries the signature.
- Use structured logging with explicit field boundaries: adopt a logging library that supports structured output (e.g., key-value pairs) so parsers do not rely on fragile line-based splitting.
Example 1: Safe Hmac computation and structured logging in Actix using the hmac and sha2 crates, with sanitized output:
use actix_web::{web, HttpResponse};
use hmac::{Hmac, Mac};
use sha2::Sha256;
use serde_json::json;
// Type alias for Hmac-SHA256
type HmacSha256 = Hmac<Sha256>;
async fn handle_request(query: web::Query<std::collections::HashMap<String, String>>) -> HttpResponse {
// Canonicalize and sort keys to ensure deterministic signing
let mut keys: Vec<&String> = query.keys().collect();
keys.sort_unstable();
let message: String = keys.iter().map(|k| format!("{}:{}", k, query[*k].replace('\n', "\\n"))).collect();
let secret = b"super-secret-key"; // use env/secrets in practice
let mut mac = HmacSha256::new_from_slice(secret).expect("Hmac can take key of any size");
mac.update(message.as_bytes());
let result = mac.finalize();
let signature = hex::encode(result.into_bytes());
// Structured log: keep raw input separate from signature
let log_entry = json!({
"endpoint": "/example",
"params": query.iter().map(|(k, v)| (k.as_str(), v.replace(['\n', '\r'], ""))).collect:: ?log_entry);
println!("{}", log_entry); // illustrative
HttpResponse::Ok().body("ok")
}
Example 2: Middleware approach to canonicalize and sign without leaking raw control characters into logs:
use actix_web::{dev::ServiceRequest, Error};
use std::future::{ready, Ready};
fn sanitize_for_log(value: &str) -> String {
value.replace(['\n', '\r', '\u{0000}'], "")
}
// Example signature builder used within request pipeline
fn build_hmac_signature(headers: &actix_web::http::HeaderMap, path: &str) -> String {
use hmac::{Hmac, Mac};
use sha2::Sha256;
type HmacSha256 = Hmac<Sha256>;
let secret = b"super-secret-key";
let mut mac = HmacSha256::new_from_slice(secret).expect("valid");
let canonical = format!("{}:{}", path, sanitize_for_log(headers.get("x-request-id").map_or("", |v| v.to_str().unwrap_or("")) ));
mac.update(canonical.as_bytes());
hex::encode(mac.finalize().into_bytes())
}