zsh-paste-guard

March 15, 2026 · View on GitHub

License: GPL-3.0 test Shell: zsh 5.1+ MITRE ATT&CK: T1204.004

https://github.com/user-attachments/assets/428fd671-cd7a-4485-bb1b-83f1978b78f5

zsh plugin that intercepts pasted commands and requires typed confirmation before execution.

Threat

MITRE ATT&CK T1204.004 (User Execution: Malicious Copy and Paste) describes attacks where adversaries trick users into copying and pasting malicious commands into a terminal. The most common variant is ClickFix: fake error messages or CAPTCHA prompts instruct victims to open a terminal and paste a provided "fix" that actually executes malware.

Note

The ESET H1 2025 Threat Report found a 517% surge in ClickFix attacks between H2 2024 and H1 2025, making it the second most common attack vector after phishing. Nation-state groups from North Korea, Russia, Iran, and Pakistan have adopted ClickFix in their initial access toolkits.

paste-guard mitigates T1204.004 by detecting pasted input through bracketed paste mode, displaying the command for review, and blocking execution until the user types a confirmation phrase. The confirmation prompt reads from /dev/tty, so it cannot be satisfied by piped or scripted input.

Install

Manual
make install
Oh My Zsh
git clone https://github.com/stefanoamorelli/zsh-paste-guard.git \
  ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-paste-guard

Then add zsh-paste-guard to the plugins array in your .zshrc:

plugins=(... zsh-paste-guard)
zinit
zinit light stefanoamorelli/zsh-paste-guard
antigen
antigen bundle stefanoamorelli/zsh-paste-guard
zplug
zplug "stefanoamorelli/zsh-paste-guard"
Sheldon
[plugins.zsh-paste-guard]
github = "stefanoamorelli/zsh-paste-guard"

Configuration

Set these environment variables in your .zshrc before sourcing the plugin.

VariableDefaultDescription
PASTE_GUARD_MODEconfirmconfirm shows the command and asks for typed confirmation. strict blocks all pasted commands unless PASTE_GUARD_ALLOW_PASTE=1 is exported.
PASTE_GUARD_ALLOW_PASTE(unset)Only used in strict mode. Set to 1 to allow pasting (still requires typed confirmation).
PASTE_GUARD_CONFIRM_TEXTI understandPhrase the user must type to confirm execution
PASTE_GUARD_WARNING_MESSAGEYou pasted this command from outside the terminal.\nOnly run commands you fully understand.Warning shown when a paste is detected

Basic example:

export PASTE_GUARD_CONFIRM_TEXT="run it"
export PASTE_GUARD_WARNING_MESSAGE="This command was pasted.\nReview it before running."
Advanced: per-team configuration with documentation links

You can set different confirmation phrases per environment and include links to your internal documentation in the warning message:

# In your team's shared .zshrc or shell profile
export PASTE_GUARD_CONFIRM_TEXT="I have reviewed this command"
export PASTE_GUARD_WARNING_MESSAGE="You pasted a command from outside the terminal.
Do NOT run commands you do not fully understand.
Review your team's security policy: https://yourcompany.atlassian.net/wiki/spaces/SEC/pages/123456/Terminal+Safety+Policy"

You can also set the confirmation text dynamically based on context:

# Different confirmation text for production vs staging
if [[ "$ENV" == "production" ]]; then
  export PASTE_GUARD_CONFIRM_TEXT="I accept production risk"
  export PASTE_GUARD_WARNING_MESSAGE="You are pasting a command in a PRODUCTION environment.
Confirm you have read: https://yourcompany.atlassian.net/wiki/spaces/OPS/pages/789/Production+Runbook"
else
  export PASTE_GUARD_CONFIRM_TEXT="ok"
fi

Strict mode

Strict mode completely blocks pasted commands — there is no confirmation prompt, no way to proceed. This is useful for non-technical users (PMs, designers, support staff) who may type the confirmation phrase without understanding what they are pasting.

Enable it in your team's shared shell profile:

export PASTE_GUARD_MODE=strict

When a paste is detected, the user sees the blocked command and a message telling them pasting is disabled. There is no option to proceed.

Developers who need to paste commands can opt in per-session:

export PASTE_GUARD_ALLOW_PASTE=1

This falls through to the normal confirm flow — the command is shown and the user must still type the confirmation phrase. The env var is not persisted across sessions unless added to .zshrc.

Internals

paste-guard hooks into three zsh mechanisms:

  1. Bracketed paste mode (zsh 5.1+, enabled by default). When text is pasted, the terminal wraps it in escape sequences (\e[200~...\e[201~). Zsh routes this through the bracketed-paste ZLE widget instead of processing each character individually. paste-guard overrides this widget to set a flag on paste.

  2. accept-line widget override. When the user presses Enter, paste-guard checks the flag. If it was a paste, the command is printed for review and execution is blocked until confirmation. If the user typed the command, it runs immediately with no friction.

  3. /dev/tty confirmation. The confirmation prompt reads directly from the terminal device, not from stdin. An attacker cannot embed the confirmation phrase inside the pasted payload or pipe it through a script.

Compatibility

RequirementDetails
Shellzsh 5.1+ with ZLE
macOSCatalina (10.15) and later (zsh is the default shell)
LinuxAny distribution with zsh installed
BSDs / WSLSupported via zsh
TerminalsTerminal.app, iTerm2, Kitty, Ghostty, Alacritty, GNOME Terminal, Konsole, Windows Terminal, xterm
DependenciesNone. Uses only zsh builtins and ZLE. No Oh My Zsh or other framework required.

Uninstall

make uninstall

References

License

GPL-3.0

Copyright (c) 2026 Stefano Amorelli stefano@amorelli.tech