Log injection¶
ID: rust/log-injection
Kind: path-problem
Security severity: 2.6
Severity: error
Precision: medium
Tags:
- security
- external/cwe/cwe-117
Query suites:
- rust-security-extended.qls
- rust-security-and-quality.qls
Click to see the query in the CodeQL repository
If unsanitized user input is written to a log entry, a malicious user may be able to forge new log entries.
Forgery can occur if a user provides some input with characters that are interpreted when the log output is displayed. If the log is displayed as a plain text file, then new line characters can be used by a malicious user. If the log is displayed as HTML, then arbitrary HTML may be included to spoof log entries.
Recommendation¶
User input should be suitably sanitized before it is logged.
If the log entries are in plain text, then line breaks should be removed from user input using String::replace
or similar. Care should also be taken that user input is clearly marked in log entries.
For log entries that will be displayed in HTML, user input should be HTML-encoded before being logged, to prevent forgery and other forms of HTML injection.
Example¶
In the first example, a username, provided by the user via command line arguments, is logged using the log
crate. If a malicious user provides Guest\n[INFO] User: Admin\n
as a username parameter, the log entry will be split into multiple lines, where the second line will appear as [INFO] User: Admin
, potentially forging a legitimate admin login entry.
use std::env;
use log::info;
fn main() {
env_logger::init();
// Get username from command line arguments
let args: Vec<String> = env::args().collect();
let username = args.get(1).unwrap_or(&String::from("Guest")).clone();
// BAD: log message constructed with unsanitized user input
info!("User login attempt: {}", username);
}
In the second example, String::replace
is used to ensure no line endings are present in the user input before logging.
use std::env;
use log::info;
fn sanitize_for_logging(input: &str) -> String {
// Remove newlines and carriage returns to prevent log injection
input.replace('\n', "").replace('\r', "")
}
fn main() {
env_logger::init();
// Get username from command line arguments
let args: Vec<String> = env::args().collect();
let username = args.get(1).unwrap_or(&String::from("Guest")).clone();
// GOOD: log message constructed with sanitized user input
let sanitized_username = sanitize_for_logging(username.as_str());
info!("User login attempt: {}", sanitized_username);
}
References¶
OWASP: Log Injection.
Common Weakness Enumeration: CWE-117.