Skip to content

properties/csv/tsv/shell output encoders don't strip terminal escape sequences #2901

Open

Description

@carfeii

reported on 8 Aug 2026 via https://github.com/mikefarah/yq/security/advisories/GHSA-pw25-v448-3fgf:

Description
yq's -o properties, -o csv, -o tsv, and -o shell output formats write a scalar value's string content directly to stdout with no filtering of control characters. yq's other four output formats (yaml, json, xml, toml) are not affected, because escaping control characters is an inherent, spec-mandated part of correctly serializing those formats, and the libraries yq uses for them already do this correctly.

Since a source document's string values have no character restrictions, and running yq to convert or extract values from a document is the tool's ordinary use, processing any document containing an escape sequence embedded in a string value with one of the four affected output formats writes that sequence to the user's terminal, where it is interpreted live by the terminal emulator.

Vulnerable code

  • pkg/yqlib/encoder_properties.go: Encode() and doEncode() write node.Value directly (only conditionally wrapping in %q if the value contains a space, no control-character handling).
  • pkg/yqlib/encoder_csv.go: encodeRow() passes child.Value directly to encoding/csv's Writer.Write(), shared by both the csv and tsv formats via a configurable separator.
  • pkg/yqlib/encoder_shellvariables.go: doEncode()'s quoteValue() correctly handles POSIX single-quote escaping (to prevent shell syntax injection if the output is later eval'd) but has no control-character filtering. Notably, the sibling function appendPath() (used for the shell variable name) already deliberately strips non-ASCII and ASCII control characters, with a code comment explaining why; the value itself never received the same treatment.

Proof of Concept

(available upon request)

Impact

An attacker who can get a victim to process a crafted document (a config file in a repository, a downloaded file, a CI/CD artifact, a third-party Helm chart or similar) with yq -o properties, -o csv, -o tsv, or -o shell can inject terminal escape sequences into the victim's terminal.

Patches / Fix

A fix has been written and validated (a PR will follow this advisory). It adds a shared sanitizeControlChars helper in pkg/yqlib/utils.go and applies it at each of the three affected encoders' scalar-value points, before their existing format-specific quoting logic runs. Re-tested against all four affected formats after the fix: the injected escape bytes are fully removed, only harmless printable text remains, and the project's existing test suite passes unchanged (two unrelated, pre-existing test failures were confirmed via git stash to also occur before this fix).

Workarounds

None identified; avoid piping yq -o properties/csv/tsv/shell output from untrusted documents directly to an interactive terminal until patched, or strip control characters from the output yourself (e.g. | tr -d '\000-\010\013\014\016-\037\177', preserving tab and newline) as a temporary mitigation.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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