Innspark Security Research
fzf is a widely used command-line fuzzy finder for selecting files, searching command history and filtering process lists. It brings those searches into Bash, zsh, Fish, Vim and Neovim, and is distributed through Homebrew and major Linux package repositories. Its GitHub repository had about 83,600 stars on 15 October 2026. The affected tmux wrapper and zsh completion script run with the same permissions as the user's shell.
TL;DR
Innspark Security Research identified two vulnerabilities in fzf's shell integrations. An attacker-controlled layout argument could make fzf-tmux execute commands as the invoking user. In zsh completion, a predictable temporary path could let another local user overwrite files or intercept completion output where OS protections and directory permissions allowed it. Both affect fzf 0.74.4 and earlier and are fixed in 0.74.5. Update the shell scripts along with the binary.
1. A layout argument becomes shell code
-l 50 and -l50 request the same layout. Vulnerable fzf-tmux versions validated only the first. The attached form passed everything after the option letter into Bash arithmetic. [1]

For left (-l) and up (-u) layouts, fzf-tmux evaluates expressions such as size=$((max - size)) or $((100 - size)). Bash interprets the unchecked value as part of the calculation, allowing a layout argument to execute commands.
How Bash evaluates the supplied size
Bash evaluates a referenced variable's value as an arithmetic expression. An array subscript within that expression can trigger command substitution. Quoting the argument keeps it intact when it is passed to the wrapper, but does not prevent this later evaluation. [4]

On a vulnerable copy of fzf-tmux, the following argument triggers the same evaluation and prints a marker to standard error. It is a harmless adaptation of the advisory's published PoC:

The advisory confirms this behavior in fzf 0.74.4 with a stub fzf executable. The arithmetic evaluation does not require a tmux session. See the public PoC. [1]
Injecting tmux popup options

The popup command expands $opt without quotes, so spaces in a geometry value can introduce additional tmux flags. The advisory demonstrates -e BASH_ENV=, which causes the launched non-interactive Bash process to source an attacker-controlled file. This path requires a popup invocation and a payload file that the Bash process can read. [1]
Both paths require the victim to invoke fzf-tmux with an attacker-controlled layout argument. That can happen when a wrapper or editor integration takes the value from less-trusted configuration. Any injected command runs with the invoking user's privileges.
The allowlist fix

The patch applies the existing allowlist to attached values, rejecting shell syntax and spaces before arithmetic evaluation or the tmux call. The popup call still expands $opt without quotes; the recommended conversion to an argument array was not adopted. The allowlist is therefore the only barrier against flag injection through geometry values. [1, 5]
2. A predictable FIFO redirects completion output
In zsh, fzf's trigger completion, typically invoked with **, sends candidates through a named pipe. For commands such as kill, ssh and export, vulnerable versions created that pipe at a path based on the shell's process ID. [2]

If the selected temporary directory is shared, another local user can create the predicted path first. In a sticky directory such as /tmp, the victim cannot remove that attacker-owned entry. mkfifo then fails because the path exists, but the helper ignores both failures and continues to the output redirection.
Where OS protections permit it, a planted symlink redirects the completion stream into a file writable by the victim, truncating that file. A planted FIFO can instead expose the candidate stream to a reader or leave the writer waiting. The exposed data is the completion list, which can include process names, hostnames or variable names. The attacker can prepare the entry in advance; winning a race is unnecessary.
How file overwrite can lead to execution
For kill completion, the stream comes from ps output, including process names that other local users can influence. If a planted symlink redirects the stream into the victim's shell startup file, commands embedded in those names may be written into the file and run when a later shell sources it. This requires a successful overwrite and valid shell syntax in the resulting file. [2]
The fix creates a private directory

mktemp creates the directory atomically with permissions that exclude other users. The helper stops if FIFO creation fails, and cleanup removes the directory. Another local user can no longer create the FIFO entry before the victim. [2, 11]
Exposure and mitigations
Modern Linux defaults block the overwrite path
On a default modern Linux host, fs.protected_symlinks blocks the cross-user symlink overwrite described here. Exploitation depends on the relevant protections being disabled or absent. systemd has shipped fs.protected_hardlinks=1 and fs.protected_symlinks=1 since 2013; later defaults also set fs.protected_regular=1 and fs.protected_fifos=1. The latter controls further restrict opens of attacker-owned files and FIFOs in sticky shared directories. [2, 6, 7, 8]
Check the effective sysctl values on systems where these defaults may have been changed. The hardlink setting is part of systemd's defaults; the reported overwrite uses a symlink.
macOS normally uses a private temporary directory
macOS sets TMPDIR to a per-user temporary directory by default. With that directory and its normal permissions, another user cannot plant the FIFO path, so the cross-user attack is not reachable in the default setup. If TMPDIR is unset or points to a shared location such as /tmp, another user may be able to plant the path. [9]
The built-in popup option
For popup workflows, fzf --popup avoids the fzf-tmux argument parser. The --popup name was introduced in 0.71.0; --tmux remains an alias. The zsh completion fix still requires an updated completion script. [10]
Updating fzf and bundled copies
Upgrade to fzf 0.74.5 or later, or a distribution package that explicitly backports both fixes. The following package listings were checked on 15 October 2026:

Check the binary version and the wrapper paths visible to the shell:

Also inspect the fzf checkout used by each editor or plugin manager, and the path sourced by .zshrc. A new binary can coexist with an old bin/fzf-tmux or shell/completion.zsh. Update each bundled copy, then restart the shell or reload the corrected completion script.
Disclosure timeline

The public advisories do not state the private-report or patch-commit dates.
Credits
Research and reporting: Sai Sreewathsa Kovalluri, Shon Babu and Kannan K of Innspark Security Research. Thanks to fzf maintainer Junegunn Choi for addressing both reports and publishing the fixes.
References
1. fzf-tmux advisory and public PoC
https://github.com/junegunn/fzf/security/advisories/GHSA-w6x2-f5m4-xw82#poc
2. zsh completion advisory
https://github.com/junegunn/fzf/security/advisories/GHSA-7rj6-7pqx-v7rm
3. fzf repository, usage and integration documentation
https://github.com/junegunn/fzf
4. GNU Bash manual, Shell Arithmetic
https://www.gnu.org/s/bash/manual/bash.html#Shell-Arithmetic
5. fzf-tmux source
https://github.com/junegunn/fzf/blob/master/bin/fzf-tmux
6. systemd current sysctl defaults
https://github.com/systemd/systemd/blob/main/sysctl.d/50-default.conf
7. systemd v208 sysctl defaults (2013)
https://github.com/systemd/systemd/blob/v208/sysctl.d/50-default.conf
8. Linux kernel documentation, /proc/sys/fs/
https://www.kernel.org/doc/html/latest/admin-guide/sysctl/fs.html
9. Apple, temporary directory for the current user https://developer.apple.com/documentation/foundation/filemanager/temporarydirectory
10. fzf 0.71.0 release, --popup name and --tmux alias
https://github.com/junegunn/fzf/releases/tag/v0.71.0
11. fzf 0.74.5 security release
https://github.com/junegunn/fzf/releases/tag/v0.74.5
12. Homebrew fzf package
https://formulae.brew.sh/formula/fzf
13. Arch Linux Extra fzf package (x86_64)
https://archlinux.org/packages/extra/x86_64/fzf/
