CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



GHSA-8QX3-8GM5-9CJ2

GHSA-8QX3-8GM5-9CJ2: Terminal Escape-Sequence Injection in pickem

Alon Barad
Alon Barad
Software Engineer

Aug 25, 2026·6 min read·16 visits

Executive Summary (TL;DR)

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).

Vulnerability Overview

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.

Root Cause Analysis

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.

Code Analysis

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 Methodology

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.

Impact Assessment and Severity

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.

Remediation and Detection Strategy

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@latest

If 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.

Official Patches

calebogden/pickem-ossv1.0.7 Security Comparison Range
calebogden/pickem-ossRaw Security Patch

Technical Appendix

CVSS Score
7.8/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H

Affected Systems

CLI tools using the pickem libraryNode.js CLI environments with user-supplied prompts
AttributeDetail
CWE IDCWE-150
Attack VectorLocal / Network-Adjacent (via external inputs like branch names or PR titles)
CVSS v3.1 Score7.8
EPSS ScoreN/A
Exploit StatusProof of Concept (PoC) available in official unit tests
CISA KEV StatusNot Listed
CWE-150
Improper Neutralization of Escape, Meta, or Control Characters

Vulnerability Timeline

Vulnerability identified and remediated in pickem-oss upstream repository
2026-06-14
Version 1.0.7 published to the npm registry containing the sanitization patch
2026-06-14
GitHub Advisory Database publishes GHSA-8QX3-8GM5-9CJ2
2026-06-14

References & Sources

  • [1]GitHub Advisory GHSA-8QX3-8GM5-9CJ2
  • [2]GitHub Repository for pickem-oss
  • [3]pickem-oss v1.0.7 Release Details

More Reports

•about 1 hour ago•CVE-2026-109618
9.8

CVE-2026-109618: Remote Code Execution in PHP Core via Out-of-Memory longjmp() Uninitialized Memory Access

CVE-2026-109618 (dubbed PHP2Shell) is a critical vulnerability in the PHP engine core resulting from improper out-of-memory exception handling via longjmp(). When request allocation fails mid-processing, non-local control flow bypasses cleanup procedures, leaving memory structures uninitialized or in a use-after-free state during request shutdown.

Amit Schendel
Amit Schendel
3 views•5 min read
•about 1 hour ago•CVE-2026-109619
9.2

CVE-2026-109619: Remote Code Execution in PHP Core via Stale Global State Memory Corruption (PHP2Shell)

CVE-2026-109619 (PHP2Shell) is a critical Use-After-Free vulnerability in the core PHP engine caused by improper global state cleanup during out-of-memory exception handling across persistent worker requests.

Alon Barad
Alon Barad
5 views•6 min read
•about 1 hour ago•CVE-2026-113721
4.5

CVE-2026-113721: Unsafe Link Resolution in virtualenv File Generation

In Python virtualenv prior to version 21.14.9, activation script generators and configuration writers use Path.exists() before writing files. Because Path.exists() resolves symbolic links, it returns False for dangling symlinks. Consequently, virtualenv skips unlinking pre-planted symbolic links or hard links, writing data directly to target locations outside the intended virtual environment directory.

Amit Schendel
Amit Schendel
3 views•5 min read
•9 days ago•CVE-2026-87697
8.8

CVE-2026-87697: Untrusted Deserialization in .NET PresentationCore Clipboard Handling

A remote code execution vulnerability exists in Microsoft .NET due to untrusted data deserialization within the PresentationCore component. The flaw stems from implicit auto-conversion flags during clipboard data retrieval operations.

Alon Barad
Alon Barad
31 views•5 min read
•9 days ago•CVE-2026-70007
8.8

CVE-2026-70007: Out-of-Bounds Write Vulnerability in .NET Framework and WPF Subsystem

An out-of-bounds write vulnerability in Microsoft .NET Framework, .NET runtime, and Visual Studio allows unauthenticated remote attackers to execute arbitrary code via crafted pixel-shader bytecode or auto-converted clipboard payloads.

Amit Schendel
Amit Schendel
19 views•6 min read
•10 days ago•CVE-2026-70186
7.5

CVE-2026-70186: ASP.NET Core Denial of Service Vulnerability via Framework Deadlock

ASP.NET Core contains a thread deadlock vulnerability (CWE-833) that allows an unauthenticated remote attacker to cause a denial of service over the network by exhausting server thread pool resources.

Amit Schendel
Amit Schendel
18 views•5 min read