Skip to content

Command column does not strip terminal escape sequences from process command lines, allowing injection via a crafted argv0 #950

Description

@carfeii

Summary

procs's Command column (Command::add, src/columns/command.rs) reads
each process's command line and only replaces newline and tab
characters before displaying it. No other control characters, and
specifically no ANSI/terminal escape sequences, are stripped. Since a
process's command line (including argv[0]) is set entirely by whichever
user started it, and /proc/<pid>/cmdline is world-readable on Linux
regardless of process ownership, any local unprivileged user can plant a
process whose command line contains a raw terminal escape sequence. When
another user runs procs, a routine diagnostic action that inherently
displays every visible process rather than one taken with awareness of
viewing untrusted content, that sequence reaches their terminal
unmodified. The only ANSI-aware helper in the codebase
(util::ansi_trim_end) exists for measuring the width of procs's own
styling codes and does not neutralize attacker-supplied content.

Validated against v0.14.12.

POC

(available upon request)

Impact

I validated this by spawning a detached process (subprocess.Popen
with executable= and a crafted argv[0], so the command that ran
was a harmless sleep) whose command line contained a raw OSC 52
(clipboard-write) escape sequence wrapping a benign base64-encoded
marker. Running procs against it and capturing its raw output
confirmed the exact injected byte sequence appears in procs's own
output stream, unmodified. I used a benign clipboard-write marker
specifically to confirm the sequence reaches output unstripped, rather
than a more aggressive payload; the specific range of what an
injected OSC/CSI sequence can do depends on the victim's terminal
emulator and was not enumerated further.

Suggested Fix

Strip or escape control characters, particularly the ESC (0x1b) byte,
from process command-line content before display, alongside the
existing newline/tab replacement. The console crate (already a
dependency, used elsewhere via strip_ansi_codes) could be used for
this.

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