Aug 25, 2026·6 min read·3 visits
Unsanitized rendering of user input in the 'pickem' library allows attackers to inject terminal escape sequences, potentially leading to remote code execution through clipboard hijacking (OSC 52).
The npm package 'pickem' is vulnerable to a terminal escape-sequence injection (CWE-150). Unsanitized terminal outputs allow attackers to execute arbitrary shell commands via clipboard hijacking (OSC 52) or manipulate terminal displays through Control Sequence Introducers (CSI).
The pickem package is an autocomplete and multi-select picker utility for command-line interface (CLI) applications. It is commonly used in interactive workflows where developers select options such as Git branches, pull requests, files, or API response fields. The core functionality depends on rendering lists of choices on the terminal standard output (stdout) and capturing user selection keys.
Because CLI tools frequently ingest and display external data, the strings processed by pickem often originate from untrusted or attacker-controllable sources. In versions prior to 1.0.7, the package printed these strings directly to the terminal emulator without sanitizing control characters. This lack of sanitization exposes users to terminal escape-sequence injection, categorized under CWE-150.
When a terminal emulator processes stdout, it interprets specific non-printable characters as functional commands. By injecting raw ANSI/VT100 escape codes and C0/C1 control characters into an item's label, an attacker can manipulate the terminal session. This enables capabilities ranging from clipboard hijacking to complete visual spoofing of the CLI layout.
The primary defect in pickem versions prior to 1.0.7 is the absence of input sanitation at the terminal output boundary. During rendering, the library uses a core 'chrome' builder located in src/core/chrome.ts to format and write the interactive rows to standard output. While inactive rows were rendered completely raw, active rows utilized a generic utility called stripAnsi.
However, standard ANSI-stripping utilities like stripAnsi are typically designed only to remove Select Graphic Rendition (SGR) sequences. These SGR sequences control visual elements like text color and background attributes. Traditional ANSI strippers fail to target raw C0 and C1 control characters or complex Operating System Commands (OSC).
Terminal emulators parse control characters using a state machine. For instance, receiving an ESC byte (0x1B) followed by specific sequences signals the terminal to switch modes or execute commands. By omitting a comprehensive character-by-character validation pass, pickem allowed raw control bytes—such as ESC (\x1b), BEL (\x07), backspace, and carriage returns—to transition directly to the terminal emulator.
In the vulnerable versions, the library printed strings to stdout with minimal filtering. In version 1.0.7, the maintainers introduced the sanitizeDisplay function and the private helper scrubControls in src/core/width.ts to isolate and strip malicious control sequences.
Below is the implementation of the new sanitization routine:
function scrubControls(s: string): string {
return s
// Remove OSC/DCS/PM/APC/SOS and ST/BEL/EOL
.replace(/\x1b[\]P^_X][\s\S]*?(?:\x07|\x1b\\|$)/g, '')
// Remove CSI (cursor move, erase, etc.)
.replace(/\x1b\[[0-9;?]*[ -/]*[@-~]/g, '')
// Remove remaining C0/C1 and DEL control bytes
.replace(/[\x00-\x1f\x7f\x80-\x9f]/g, '')
}
export function sanitizeDisplay(str: string, { allowStyle = true }: { allowStyle?: boolean } = {}): string {
if (!allowStyle) return scrubControls(str.replace(new RegExp(SGR_RE, 'g'), ''))
const result = str
.split(SGR_RE)
.map((part, i) => (i % 2 === 1 ? part : scrubControls(part)))
.join('')
return /\x1b\[/.test(result) ? `${result}\x1b[0m` : result
}The scrubControls helper employs three distinct regular expressions. The first regex targets Operating System Commands (OSC), Device Control Strings (DCS), and other system-level directives. The second regex neutralizes Control Sequence Introducers (CSI), which govern terminal movement. The third regex functions as a catch-all for remaining C0/C1 control bytes, such as BEL (\x07) and DEL (\x7f).
This architecture ensures that legitimate user-defined styling (such as ANSI text colors) is retained while eliminating any executable escape codes. Additionally, the function appends a reset escape sequence (\x1b[0m) at the end of the string if any color sequence is detected. This prevents accidental color bleeding across other rows in the terminal display.
Exploitation of this vulnerability requires an attacker to inject escape sequences into a data source read by a vulnerable CLI tool. For example, in a collaborative development workflow, an attacker can create a Git branch containing a crafted payload. When another developer runs a CLI picker to select a branch, the payload is rendered.
One severe exploitation technique leverages the OSC 52 sequence to hijack the host operating system's clipboard. The OSC 52 sequence instructs the terminal emulator to write specified text into the clipboard. An attacker can construct a payload that places a malicious command into the clipboard silently.
When the victim subsequently uses a shortcut to paste inside their terminal, the malicious command executes immediately. Another technique involves using CSI sequences to reposition the cursor. By moving the cursor up and erasing preceding lines, an attacker can overwrite application outputs, spoofing verification screens or hiding security alerts.
The impact of terminal escape-sequence injection depends heavily on the capabilities of the host terminal emulator. Emulators supporting OSC 52 clipboard modifications expose the system to arbitrary command execution. Because developers frequently execute CLI tools within administrative or elevated development contexts, this vector can lead to immediate host compromise.
For terminal emulators that disable OSC 52 or restrict clipboard writes, the impact shifts toward visual integrity compromise and denial of service. Attackers can execute CSI-based UI spoofing to mislead developers into running insecure actions. For instance, a spoofed prompt can trick a developer into approving a malicious deployment or committing to a compromised branch.
Furthermore, continuous injection of BEL (\x07) or backspace characters can degrade terminal performance or trigger excessive system noise. This creates a local denial-of-service condition that renders the shell session unusable until the terminal process is restarted.
The primary remediation for this vulnerability is upgrading the pickem dependency to version 1.0.7 or newer. This release implements the sanitizeDisplay function globally across all rendering pathways. This covers inactive rows, active rows, and custom formatting wrappers within the application.
To upgrade the package in a Node.js project, run the following command in your repository terminal:
npm install pickem@latestIf upgrading immediately is not feasible, implement a pre-rendering sanitization wrapper on all external strings passed to the library. Applications can utilize a utility that strips non-printable C0 and C1 characters before they are passed into the choices list. This prevents the terminal from processing downstream payloads.
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H| Attribute | Detail |
|---|---|
| CWE ID | CWE-150 |
| Attack Vector | Local / Network-Adjacent (via external inputs like branch names or PR titles) |
| CVSS v3.1 Score | 7.8 |
| EPSS Score | N/A |
| Exploit Status | Proof of Concept (PoC) available in official unit tests |
| CISA KEV Status | Not Listed |
CVE-2026-55596 is a critical DOM-based Cross-Site Scripting (XSS) vulnerability in the Plate rich-text editor framework (specifically within the @platejs/media package). The issue stems from an optimization fast-path that short-circuits safety parsing if a provider or source URL is already declared on an element. Consequently, serialized documents carrying malicious javascript: URLs bypass protocol sanitization and are loaded directly into iframe elements, leading to code execution.
CVE-2026-55537 is a server-side request forgery (SSRF) and time-of-check time-of-use (TOCTOU) vulnerability in the PraisonAI multi-agent framework before version 4.6.58. The flaw exists in the job-submission component's webhook URL validation logic. When DNS resolution fails during verification, the application fails open, enabling attackers to register unresolvable URLs. When a completed job triggers the webhook, the application performs a fresh DNS resolution that attackers can manipulate to target internal resources.
Prior to version 5.0.8, django CMS fails to respect dynamically declared Vary HTTP headers in its internal page cache. This allows remote attackers to bypass authorization, leak sensitive information across user sessions, or poison the page cache by sending requests with custom headers.
A security vulnerability in the github.com/gorilla/websocket Go library allows remote attackers to predict client-to-server frame masking keys. This occurs because the library generates 32-bit mask keys using Go's non-cryptographically secure pseudo-random number generator (math/rand). Predicting these keys enables adversaries to bypass proxy-based security protections, facilitating HTTP request smuggling and cache poisoning attacks.
MHSanaei 3X-UI is a web control panel for managing Xray-core servers. In versions prior to 3.3.1, an authenticated administrator can abuse database import functions or raw template config fields to overwrite or append to arbitrary files on the host filesystem. This is achieved by altering the Xray log configuration variables to target system files, leveraging logging components to inject payloads.
Cloudreve is vulnerable to an incorrect authorization bypass. When listing files, Cloudreve returns a context_hint (represented as a UUID) to the client. If this context hint is replayed on the /file/url or /file/thumb routes, Cloudreve's database file system caches the shareNavigatorState containing the loaded share root. Within the cache lifetime (TTL of 300 seconds), if the user re-requests the same file with the cached hint, the system restores the state and completely bypasses the root security checks (which validate share expiration, remaining download limits, owner status, and passwords). This allows unauthorized users to continue generating signed file URLs and downloading files even after a share has been deleted, has expired, or has reached its download limit.