zsh-paste-guard
March 15, 2026 · View on GitHub
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.
| Variable | Default | Description |
|---|---|---|
PASTE_GUARD_MODE | confirm | confirm 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_TEXT | I understand | Phrase the user must type to confirm execution |
PASTE_GUARD_WARNING_MESSAGE | You 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:
-
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 thebracketed-pasteZLE widget instead of processing each character individually.paste-guardoverrides this widget to set a flag on paste. -
accept-linewidget override. When the user presses Enter,paste-guardchecks 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. -
/dev/ttyconfirmation. 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
| Requirement | Details |
|---|---|
| Shell | zsh 5.1+ with ZLE |
| macOS | Catalina (10.15) and later (zsh is the default shell) |
| Linux | Any distribution with zsh installed |
| BSDs / WSL | Supported via zsh |
| Terminals | Terminal.app, iTerm2, Kitty, Ghostty, Alacritty, GNOME Terminal, Konsole, Windows Terminal, xterm |
| Dependencies | None. Uses only zsh builtins and ZLE. No Oh My Zsh or other framework required. |
Uninstall
make uninstall
References
- MITRE ATT&CK T1204.004 - User Execution: Malicious Copy and Paste
- ClickFix Attacks Surge 517% in H1 2025 - Infosecurity Magazine
- ESET Threat Report: ClickFix Surges, Spreads Ransomware and Other Malware
- Bracketed Paste Mode - cirw.in
License
Copyright (c) 2026 Stefano Amorelli stefano@amorelli.tech