Securing Clipboard Privacy on Wayland and Hyprland with a Custom wl-paste Script

TL;DR: Wayland/Hyprland clipboard managers can leak secrets.

Solution: Lower history size. Wipe history on reboot. Use a secure watcher script to block sensitive data. Disable clipboard history entirely for maximum security.

Securing clipboard data on Wayland

I’ve been running Wayland for a while now, specifically with Hyprland, and overall I’m really happy with the switch from X11. The rendering feels smoother, the security model is much stronger, and the compositors are catching up fast in terms of features.

But along the way I stumbled on a subtle problem: clipboard privacy.

The issue isn’t Wayland itself. In fact, Wayland is designed to be more secure than X11, applications don’t have the same free-for-all access to your clipboard content. The problem comes from how most users (myself included, at first) integrate clipboard managers like cliphist, clipman, copyq, or clipse into their workflow.

If you follow the official Hyprland wiki on Clipboard Manager integration, you’ll often see something like this in your config:

# cliphist
exec-once = wl-paste --watch cliphist store

# clipman
exec-once = wl-paste -t text --watch clipman store --no-persist

# clipvault
exec-once = wl-paste --watch clipvault store

# clipse
exec-once = clipse -listen

# copyq
exec-once = copyq --start-server

# wl-clip-persist
exec-once = wl-clip-persist --clipboard regular

It’s convenient. Every piece of text you copy is automatically added to your clipboard history, and you can later search or browse it with tools like rofi, fuzzel, or tofi.

The problem? Sometimes what you copy is highly sensitive: passwords, SSH private keys, API tokens, crypto wallet seeds, work related stuff. All of that goes straight into your clipboard history, stored unencrypted in a local SQLite database. Anyone (or anything) with access to your account can read it. And if you display your history in a GUI or list it in the terminal, you’re even vulnerable to simple shoulder surfing.

That’s what motivated me to write this article. I’ll walk you through:

  • Why the default clipboard integrations are risky.
  • How clipboard managers like cliphist store your data.
  • Simple hardening tips (limit history length, auto-wipe on reboot).
  • And most importantly, how I built a custom wl-paste watcher script that filters out sensitive content before it ever reaches your clipboard history.

Understanding the Risk of Clipboard History

Clipboard management has always been a balancing act between convenience and security. To see why this matters so much on Wayland, let’s compare:

X11 vs. Wayland

  • X11: Any running application can peek at your clipboard at any time, no questions asked. This was a huge security hole, but everyone got used to it.
  • Wayland: Applications are sandboxed, they can’t just grab your clipboard without focus. This is objectively safer.

So far, so good. But here’s the catch:

The Clipboard Manager Problem

To regain convenience (clipboard history, fuzzy searching, GUI pickers), most Wayland users install a clipboard manager such as: cliphist, clipman, copyq, clipse, clipvault

And then they wire it up with wl-paste like so:

exec-once = wl-paste --watch cliphist store

From that moment on, everything you copy is automatically stored: including secrets.

Real Attack Vectors

1. Clipboard History Dumping

Anyone with access to your user account can run:

cliphist list | grep "BEGIN OPENSSH"

…and immediately extract your private keys, API tokens, or even 12/24-word crypto wallet seed phrases.

2. Shoulder Surfing

If you browse history with a GUI like rofi, wofi, fuzzel, or tofi, you’re effectively flashing all your sensitive data in cleartext. One glance, screenshot, or screen share, and it’s compromised.

3. Unencrypted Storage

Clipboard history isn’t just ephemeral. For instance, cliphist stores everything by default in an unencrypted SQLite database at: ~/.cache/cliphist/db or ~/.cache/cliphist.db

Anyone with filesystem access can open this file and scroll through hundreds of past entries.

The cliphist --help output makes it clear:

usage:
  $ cliphist <store|list|decode|delete|delete-query|wipe|version>
options:
  -config-path (default ~/.config/cliphist/config)
    overwrite config path to use instead of cli flags
  -db-path (default ~/.cache/cliphist/db)
    path to db
  -max-dedupe-search (default 100)
    maximum number of last items to look through when finding duplicates
  -max-items (default 750)
    maximum number of items to store
  -preview-width (default 100)
    maximum number of characters to preview

That means you could be carrying around 750 past clipboard entries: completely unprotected.

Balancing Productivity vs. Security

It’s easy to see why clipboard managers are so popular. Being able to pull up something you copied 20 minutes ago, or even yesterday, is incredibly convenient. Developers, sysadmins, writers… we all benefit from a searchable clipboard history.

But the reality is that you rarely need 750 past entries. Most of the time, your workflow only depends on the last handful of items. And keeping more than that only increases your attack surface.

Here are some practical mitigations that already make a big difference:

1. Lower the Clipboard History Size

By default, cliphist keeps 750 items. That’s way too much for most users. Reducing it to something like 20-50 items drastically limits exposure:

# ~/.config/cliphist/config
max-items = 50

That’s usually enough to keep what’s useful while not hoarding every copied string for weeks.

2. Wipe Clipboard History on Reboot

Another simple but powerful practice: start fresh at every reboot.

You can wipe your history automatically by adding this line to your compositor config:

exec-once = cliphist wipe

Or, for systemd users, you could drop a user service that runs cliphist wipe at startup. This ensures any sensitive data accidentally stored is cleared out with every new session.

3. Selective Filtering (The Smart Way)

Of course, the best solution is to never store sensitive data in the first place. That’s where my custom script comes in.

Instead of blindly storing everything with:

exec-once = wl-paste --watch cliphist store

…I pipe the clipboard through a secure filter script. It automatically detects when the copied content looks like a password, SSH key, API token, or crypto seed: and simply refuses to add it to the history.

exec-once = wl-paste --watch ~/.config/bin/cliphist-secure-store.sh

This way you keep all the productivity benefits of clipboard history, while drastically reducing your exposure.

4. Disable Clipboard History completely (God mode)

If you don’t need clipboard history, you can disable it entirely. Simply remove the exec-once line from your compositor config.

This way will be 100% secure, but you won’t be able to search or browse your history. Nothing’s safer.

The Secure Clipboard Script

Here’s the script I use in my own Hyprland setup. It replaces the default one-liner and acts as a filter between wl-paste and cliphist. Instead of blindly storing everything, it analyzes the copied content and decides if it should be stored or discarded.

#!/usr/bin/env bash
#
# Secure clipboard watcher for Hyprland + cliphist
#

set -euo pipefail

# ---- Configuration ---------------------------------------------------------

DEBUG=0   # set to 1 for debug output, 0 for silent

PM_APPS_REGEX='(Bitwarden|bitwarden|KeePassXC|keepassxc|1Password|1password|LastPass|lastpass|Enpass|enpass|Dashlane|dashlane|NordPass|nordpass|gnome-keyring|kwallet)'
SEED_COUNTS_REGEX='^(12|24)$'
KEY_MARKERS_REGEX='(BEGIN (OPENSSH|RSA|DSA|EC|ENCRYPTED)? ?PRIVATE KEY|ssh-|ecdsa-sha2-nistp)'
JWT_REGEX='(^|[^A-Za-z0-9_-])eyJ[A-Za-z0-9_-]{10,}.[A-Za-z0-9_-]+.'
GIT_TOKEN_REGEX='(gh[pous]_[A-Za-z0-9]{20,}|pat_[A-Za-z0-9]{20,})'
GOOGLE_TOKEN_REGEX='(^|[^A-Za-z0-9_-])ya29.[A-Za-z0-9_-]+'
HEX64_REGEX='^[A-Fa-f0-9]{64,}$'
B64_REGEX='^[A-Za-z0-9+/=]{40,}$'
ENTROPIC_REGEX='[A-Za-z0-9!@#$%^&*()_+=-]{16,}'

log_debug() {
    (( DEBUG == 1 )) && echo "[DEBUG] $*" >&2
}

# ---- Helpers ---------------------------------------------------------------

focused_app_is_pm() {
    local cls
    cls="$(hyprctl activewindow -j 2>/dev/null | jq -r '.class // ""')"
    log_debug "Focused app: '$cls'"
    [[ "$cls" =~ $PM_APPS_REGEX ]]
}

text_is_sensitive() {
    local data="$1"

    local wc_words
    wc_words="$(wc -w <<< "$data" | tr -d '[:space:]')"

    if [[ "$wc_words" =~ $SEED_COUNTS_REGEX ]]; then
        log_debug "Blocked: seed phrase ($wc_words words)"
        return 0
    fi

    if grep -qiE "$KEY_MARKERS_REGEX" <<< "$data"; then
        log_debug "Blocked: private key marker"
        return 0
    fi

    if grep -qE "$JWT_REGEX" <<< "$data"; then
        log_debug "Blocked: JWT token"
        return 0
    fi

    if grep -qE "$GIT_TOKEN_REGEX" <<< "$data"; then
        log_debug "Blocked: GitHub token"
        return 0
    fi

    if grep -qE "$GOOGLE_TOKEN_REGEX" <<< "$data"; then
        log_debug "Blocked: Google token"
        return 0
    fi

    if grep -qE "$HEX64_REGEX" <<< "$data"; then
        log_debug "Blocked: long hex string"
        return 0
    fi

    if grep -qE "$B64_REGEX" <<< "$data"; then
        log_debug "Blocked: long base64 string"
        return 0
    fi

    if grep -qE "$ENTROPIC_REGEX" <<< "$data"; then
        log_debug "Blocked: entropy heuristic"
        return 0
    fi

    return 1
}

# ---- Main flow -------------------------------------------------------------

clip_content=$(cat)

if focused_app_is_pm; then
    log_debug "Skipped: password manager focused"
    exit 0
fi

if text_is_sensitive "$clip_content"; then
    exit 0
fi

log_debug "Stored in cliphist: '${clip_content:0:60}'..."
printf "%s" "$clip_content" | cliphist store

How It Works

1. Password Manager Detection

Using hyprctl activewindow, the script checks if the focused application is a password manager (KeePassXC, Bitwarden, 1Password, etc.). If yes, clipboard storage is skipped entirely.

You can add your own apps to the list if you want to allow them to store sensitive data.

PM_APPS_REGEX='(Bitwarden|bitwarden|KeePassXC|keepassxc|1Password|1password|LastPass|lastpass|Enpass|enpass|Dashlane|dashlane|NordPass|nordpass|gnome-keyring|kwallet)'

2. Sensitive Data Patterns

The script scans the clipboard content against common secret formats:

  • 12/24-word crypto wallet seeds
  • SSH private keys (BEGIN OPENSSH PRIVATE KEY)
  • JWT tokens (eyJ…)
  • GitHub personal access tokens (ghp, pat)
  • Google OAuth tokens (ya29.)
  • Long base64 or hex strings
  • High-entropy random strings (common in secrets)

If any match, the content is discarded.

3. Safe Data Storage

If the content passes the checks, it’s piped to cliphist store as usual.

4. Debug Logging

Set DEBUG=1 to see why items were blocked. Example output:

[DEBUG] Blocked: seed phrase (12 words)

Integration with Hyprland

Setting up the secure clipboard watcher is straightforward. You’ll just replace the default wl-paste --watch cliphist store line from the Hyprland wiki with your custom script.

1. Save the Script

Put the script somewhere persistent, for example:

~/.config/bin/cliphist-secure-store.sh

Make it executable:

chmod +x ~/.config/bin/cliphist-secure-store.sh

2. Update Your Hyprland Config

In your hyprland.conf, change the exec-once line to:

exec-once = wl-paste --watch ~/.config/bin/cliphist-secure-store.sh

This ensures all new clipboard events are filtered through your script before reaching cliphist.

3. Install Dependencies

The script relies on a few tools:

  • wl-clipboard: provides wl-paste and wl-copy.
  • cliphist: your clipboard history manager.
  • jq: used to parse Hyprland’s JSON output from hyprctl.

On Arch-based distros (CachyOS, Arch, Manjaro):

sudo pacman -S wl-clipboard cliphist jq

On Debian/Ubuntu-based systems:

sudo apt install wl-clipboard jq

On Fedora/RedHat-based systems:

dnf install wl-clipboard jq

4. Optional: Enable Debugging

If you want to verify the filtering works, set DEBUG=1 in the script. Then restart Hyprland, copy a secret (like an SSH key header), and check the logs:

journalctl --user -f | grep cliphist-secure-store

You should see messages like:

[DEBUG] Blocked: private key marker

Demo & Examples

Let’s put the secure clipboard watcher to the test.

1. Normal Text

Copy a harmless string:

echo "hello world" | wl-copy

Check your history:

cliphist list | head -n 1

Result: ”hello world” appears in the list as expected.

2. SSH Private Key

Now copy something that looks like a private key:

echo "-----BEGIN OPENSSH PRIVATE KEY-----" | wl-copy

Check your history again:

cliphist list | grep "OPENSSH"

Result: No match found: the script blocked it.

If DEBUG=1 is enabled, you’ll see:

[DEBUG] Blocked: private key marker

3. Crypto Seed Phrase

Try a 12-word seed:

echo "apple banana cat dog eagle flower guitar hotel island jungle kite lemon" | wl-copy

Run:

cliphist list | grep "apple"

Result: Nothing stored: seed phrases are automatically discarded.

4. Password Manager Window

Open KeePassXC, focus its window, then copy any text inside it.

Even if it’s just “test123”, the script will detect the active window’s class and skip storage.

With debug logging, you’ll see:

[DEBUG] Skipped: password manager focused

5. After a Reboot (Optional Hardening)

If you’ve set cliphist wipe to run at startup, your history will be empty on every new session:

cliphist list
# no output

This ensures nothing sensitive survives across reboots.

Limitations & Future Ideas

This setup goes a long way toward making clipboard history on Wayland safer, but it’s not a silver bullet. There are still a few caveats worth mentioning:

1. Regex and Heuristics Aren’t Perfect

  • The script blocks many common secret formats, but it’s always possible for something sensitive to slip through if it doesn’t match the patterns.
  • Conversely, some false positives can happen: a random string might look like a token and get discarded.

2. Plaintext Storage Remains

  • Even with filtering, the clipboard entries that do get stored are written to an unencrypted SQLite database (or other storage backend depending on the tool).
  • Anyone with access to your home directory can still open it and read your clipboard history.

3. Application-Specific Gaps

  • The window detection relies on class names (hyprctl activewindow -j). If your password manager or crypto wallet app uses a different class name, you’ll need to extend the regex.
  • This is easy to tweak, but it requires a bit of manual maintenance.

Future Improvements

  • Configurable rules: move regex patterns into a separate config file so users can customize without editing the script.
  • Encryption support: ideally, clipboard managers like cliphist could offer optional encryption for stored data.
  • Systemd integration: wrap the script in a systemd --user unit for easier logging, auto-restart, and enable/disable.
  • Selective wipe: add a timed auto-wipe (e.g. every 24 hours), not just at reboot.

Conclusion

Clipboard history is one of those features you don’t think twice about… until you realize how much sensitive data can end up there. On Wayland and Hyprland, the security model is stronger than X11, but integrating clipboard managers without caution reintroduces old risks: passwords, SSH keys, API tokens, and crypto seeds all sitting unencrypted in a SQLite database.

By combining four simple practices, you can dramatically reduce your exposure:

  • Lower the history size: don’t keep 750 entries when 20–50 is enough.
  • Wipe history on reboot: start every session with a clean slate.
  • Filter sensitive data with a custom watcher: never let secrets enter the history in the first place.
  • Disable clipboard history entirely: If you don’t truly need history, the safest option is to remove the clipboard manager integration from your config. Nothing will ever be saved, so there’s nothing to leak, maximum security, at the cost of convenience.

With this setup, you keep the productivity benefits of clipboard managers while avoiding the most obvious pitfalls. It’s not perfect, encryption and smarter filtering would be even better, but it’s a huge improvement over the default configuration.

If you’re running Hyprland (or any Wayland compositor) and rely on clipboard history, take a few minutes to harden your setup. Future you, and your SSH keys, passwords, and crypto wallets, will thank you.

September 30, 2025 by Julien Turbide