https://bugs.kde.org/show_bug.cgi?id=525879
Bug ID: 525879
Summary: Klipper persists clipboard contents to disk in ways
that (a) exceed the configured history size, (b)
cannot be reached through any user interface, and (c)
are created with permissive modes derived from the
ambient umask. The two settings that appear to co
Classification: Plasma
Product: plasmashell
Version First 6.7.5
Reported In:
Platform: CachyOS
OS: Linux
Status: REPORTED
Severity: normal
Priority: NOR
Component: Clipboard widget & pop-up
Assignee: [email protected]
Reporter: [email protected]
CC: [email protected]
Target Milestone: 1.0
## Summary
Klipper persists clipboard contents to disk in ways that (a) exceed the
configured history size, (b) cannot be reached through any user interface, and
(c) are created with permissive modes derived from the ambient umask. The two
settings that appear to control this do not. Password managers signal that
their clipboard data is sensitive; Klipper does not read that signal.
Each point below is independently reproducible.
## Environments tested
| | Machine A | Machine B | Machine C |
|---|---|---|---|
| OS | CachyOS (Arch) | Kubuntu 24.04.5 LTS | Fedora 44 KDE |
| Plasma | 6.7.5 | 5.27.12 (`4:5.27.12-0ubuntu0.1`) | 6.7.5 |
| Store format | `history3.sqlite` + `data/` blobs | `history2.lst` (flat file)
| `history3.sqlite` + `data/` blobs |
| umask | `0022` | `0002` | `0022` |
| Home dir mode | `700` | **`751`** | `700` |
| `klipperrc` | present | **absent — pure defaults** | **absent — pure
defaults** |
| Other local account exists | no | **yes** | no |
All values measured directly on the respective machines. Two of the three have
no `klipperrc` at all, so their behaviour is what a default installation
produces with no user configuration.
## 1. Content is retained beyond `MaxClipItems` and is unreachable by any UI
**Machine C** has **no `klipperrc` at all**, so it runs entirely on shipped
defaults:
```
$ find ~/.local/share/klipper/data -type f | wc -l
39
```
39 stored blobs on a machine where nothing was ever configured.
The default `MaxClipItems` is widely documented as 7. I cannot state that from
my own measurement — the setting had already been changed on both machines
available to me before the original value was recorded — so please check it
against the shipped default. **Whatever that default is, the blob count should
not exceed it, and the popup on machine C did not offer 39 entries.**
Supporting measurements from machine A: on 2026-08-24 the store held **319 KB
database + 696 KB WAL**; after being cleared to 24 KB it returned to **2.1 MB
WAL by 2026-09-17**, three weeks of ordinary use.
**The decisive point:** the Klipper popup displays `MaxClipItems` entries.
There is no UI to browse, search or restore anything beyond that. Content older
than the visible list is *inaccessible to the user and still present on disk*.
It provides no feature and carries the full privacy cost.
This also defeats any memory or performance justification for persistence —
storing blobs the UI cannot display does not save RAM, it spends disk.
## 2. `MaxClipItems=0` does not prevent writes (new)
```
kwriteconfig6 --file klipperrc --group General --key MaxClipItems 0
qdbus6 org.kde.klipper /klipper org.kde.klipper.klipper.reloadConfig
qdbus6 org.kde.klipper /klipper org.kde.klipper.klipper.clearClipboardHistory
```
Then copy a unique marker and search the store:
```
wl-copy "CLIPTEST-MARKER-93741"
grep -rl "CLIPTEST-MARKER-93741" ~/.local/share/klipper/
```
**Result:** the marker is found at `~/.local/share/klipper/data/<sha1>/<sha1>`.
With the history size set to zero, clipboard content is still written to disk —
not into the database, but into a separate content-addressed blob store beside
it. Documentation and community advice both describe history size 0 as the way
to disable storage. It is not.
## 3. `KeepClipboardContents=false` governs only restore-at-login
Machine A had `KeepClipboardContents=false` set, and `history3.sqlite`'s WAL
was still observed growing during a single session (1.1 MB → 1.7 MB → 2.1 MB
over roughly an hour). The setting governs whether the clipboard is restored at
next login, not whether it is recorded.
The name invites the opposite reading. Combined with §2, a user who sets both
`KeepClipboardContents=false` and `MaxClipItems=0` — which is what the
available settings suggest — still has every copied value written to disk.
## 4. `x-kde-passwordManagerHint` is emitted by applications and appears
unhandled by Klipper
KeePassXC, `wl-copy` and Firefox (`libxul.so`) all carry the
`x-kde-passwordManagerHint` marker, used to signal that clipboard content is a
secret.
On machine A the string is **present** in `/usr/bin/keepassxc`,
`/usr/bin/wl-copy` and Firefox's `libxul.so`, and **absent** from the three KDE
components that would need to act on it:
```
/usr/lib/libklipper.so.6.7.5 no match
/usr/lib/libexec/plasmashell no match
/usr/lib/qt6/qml/org/kde/plasma/private/clipboard/*.qml no match
```
These are the specific files searched with `strings`/`grep`; I have not audited
every KDE binary, and a stripped build could hide a literal. If the hint *is*
handled somewhere, the observed behaviour still contradicts it — see below.
**Scope of this claim.** What is established is the absence of the string from
those three components. The marker test in §2 used plain `wl-copy` *without*
the hint, so it does not demonstrate that hinted content is stored regardless —
that test has not been run here and is the obvious next step for anyone
reproducing this. The claim is therefore "appears unhandled", not "is ignored".
Related: KeePassXC's "clear clipboard after N seconds" does not help either
way. It clears the *clipboard*; if Klipper has already recorded the value,
clearing the source does not remove the recorded copy. The timeout protects
against the clipboard still holding the value, not against a clipboard manager
having stored it.
## 5. Store is created with ambient-umask modes — cross-user disclosure on
default Ubuntu-family installs
Machine B, stock Kubuntu 24.04.5 with two ordinary user accounts and **no
`klipperrc`** — entirely default behaviour. `umask` measured as `0002`.
```
$ namei -l ~/.local/share/klipper/history2.lst
drwxr-xr-x root root home
drwxr-x--x userA userA userA <- 751, others may traverse
drwxrwxr-x userA userA .local <- 775
drwxrwxr-x userA userA share <- 775
drwxrwxr-x userA userA klipper <- 775
-rw-rw-r-- userA userA history2.lst <- 664, 10.6 KB of clipboard history
```
Every directory in the path grants `x` to others and the file grants `r` to
others, so the permissions permit any local account to read it. **This is
established from the permission bits; nobody logged in as the second account to
read the file.** A reproducer with root can confirm behaviourally with `sudo -u
otheruser test -r <path>`, which proves access without printing the contents.
Given §4, the contents can include passwords.
Machines A and C escape this only because Arch and Fedora create home
directories at `0700`. Klipper's own directory on both is still `755` with the
database at `644` — the protection comes from the home directory, not from
Klipper.
The variable is the distribution's umask and home mode, not Klipper's
behaviour, which is identical everywhere:
| Distribution | umask | Klipper dir | Store file | Home mode | Result |
|---|---|---|---|---|---|
| CachyOS (Arch) | `022` | `755` | `644` | `700` | contained by home |
| Fedora 44 | `022` | `755` | `644` | `700` | contained by home |
| Kubuntu 24.04.5 | `0002` | `775` | `664` | `751` | **permissions allow other
local users** |
Klipper inherits whatever the umask gives it in both cases. On the Ubuntu
family that produces cross-user disclosure; elsewhere it is one `chmod` on a
home directory away from the same outcome.
`~/.ssh` and `~/.gnupg` force `0700`/`0600` regardless of umask because their
contents are sensitive. Clipboard history holds arbitrary copied text and
deserves the same treatment.
## 6. Content-addressed filenames outlive the content
Blobs in `data/` are named by the SHA1 of their contents. Demonstrated:
```
$ printf '%s' "CLIPTEST-MARKER-93741" | sha1sum
51a391c70e73b6fbee3e4d5e6f6cafccef6a726d
$ find ~/.local/share/klipper/data -type f
~/.local/share/klipper/data/51a391c70e73b6fbee3e4d5e6f6cafccef6a726d/51a391c70e73b6fbee3e4d5e6f6cafccef6a726d
```
The filename is the SHA1 of the clipboard content, with no salt and no newline.
A leftover filename therefore lets an observer confirm a guessed value by
hashing it — even after the blob itself has been deleted — and makes
low-entropy clipboard contents recoverable by brute force from the name alone.
## Impact
Any process running as the user can read clipboard values well beyond what the
UI exposes — 39 blobs on an unconfigured machine, and no upper bound was
observed in three weeks of ordinary use. On Ubuntu-family defaults the
permissions also allow other local accounts to read them. The values include
anything copied from a password manager, terminal, or browser field.
## Suggested fixes
1. **Enforce the retention limit on the blob store**, not just the visible list
— garbage-collect blobs when their entries age out.
2. **Make `MaxClipItems=0` mean no persistence**, covering `data/` as well as
the database.
3. **Honour `x-kde-passwordManagerHint`** — exclude flagged content from
history entirely.
4. **Create the store `0700`/`0600` explicitly**, as SSH and GnuPG do, rather
than inheriting the umask.
5. **Rename or document `KeepClipboardContents`** so it is not read as "do not
keep clipboard contents".
## Workaround currently in use
Replacing the blob directory with a symlink to `/dev/null` prevents the writes
without breaking the clipboard:
```
rm -rf ~/.local/share/klipper/data
ln -s /dev/null ~/.local/share/klipper/data
```
Verified: `plasmashell` does not crash, no errors are logged, `wl-paste`
continues to work normally, and a copied marker appears nowhere on disk. That a
symlink to `/dev/null` is the reliable way to disable this is itself an
indication that the supported settings do not.
--
You are receiving this mail because:
You are watching all bug changes.