Skip to content

User input in error message may poison logs with ANSI escape sequences #424

@dtolnay

Description

@dtolnay
Submitted by email from @zefr0x

When using anyhow::Result in the main function, user input can be printed unintentionally via an error's core::fmt::Display implementation when the application exits, it might print ANSI escape sequences, potentially compromising the integrity of log files and interacting with terminal emulators.

Terminals vary in supporting ANSI codes, but modern ones usually allow arbitrary changes to the terminal display including hiding logs or writing fake ones, writing clickable hyperlinks, changing the terminal title, inserting content to the system clipboard, and sending desktop notifications etc...

By itself, it might lead to presenting falsified information in logs and allow clickbaiting attacks. However, due to the huge attack surface, accompanied with another vulnerability or misconfiguration in the terminal, system clipboard, or applications reading the clipboard etc... it might result in an arbitrary code execution.

You can search "Weaponizing ANSI Escape Sequences" for more details and examples.

Similar CVEs

Possible solutions

  • Always use the Debug trait when printing error messages, as it will escape error messages from possible malicious non-visible characters by default using std::char::escape_debug.

  • Always use std::char::escape_default on output string before printing it.

PoC

[package]
name = "poc"
version = "0.1.0"
edition = "2024"

[dependencies]
anyhow = "1.0"
#[derive(Debug)]
struct MyCustomError {
    details: String,
}

impl std::error::Error for MyCustomError {}

impl core::fmt::Display for MyCustomError {
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
        write!(f, "MyCustomError: {}", self.details)
    }
}

fn validate_id(id: &str) -> Result<(), MyCustomError> {
    if id.contains("123") {
        Ok(())
    } else {
        Err(MyCustomError {
            details: String::from(format!("`{id}` is missing `123`")),
        })
    }
}

fn main() -> anyhow::Result<()> {
    let user_input = "\x1b]0;Changed Terminal Window Title\x07 \x1b[1J\x1b[4m\x1b[1;34mtest";

    validate_id(user_input)?;

    Ok(())
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions