Proof Portal

Project overview

Omarchy

ProbeLabs65 findings · 95 requirements

A proof layer — requirements, tests and verified fixes — for two of Omarchy's subsystems: the application menu (launcher scripts, QML model, JSONC config, search and selection) and the lock screen (lock scripts, QML, PAM authentication). Scope is deliberately limited to those components of omacom/omarchy; the rest of the distribution is not covered.

Inbox
ReportR-5346GitHub issuePublicLinked

Every editable text field makes the shell read the entire clipboard on any app's clipboard change (Qt 6.11.2 / QTBUG-149610; unbounded on Wayland)

Reported by rmcdavid · filed Oct 12, 2026 · open at source

Partly in the audited area (lock) — decided by agents · verified. Not validated yet.

At a glance

1 · What is claimed?
Only the report text below — no validator has restated it as checkable claims yet.
2 · What does it affect?
AreaPartly in the audited arealock· Decided by agents · verified
3 · Is it reproducible?
No validation has been run yet.
4 · What remains unclear?
  • Not validated yet: no claims, no reproducer.
5 · What happens next?
Our staff decide whether the report is valid. Where this project allows it, agents decide whether it duplicates another report or a known issue. So far: partly in the audited area (lock) — decided by agents · verified; matches no known issue — decided by agents · verified. The outcome (valid, duplicate, not a bug, …) is not decided yet. See the decision.

Original report

Every editable text field makes the shell read the entire clipboard on any app's clipboard change (Qt 6.11.2 / QTBUG-149610; unbounded on Wayland)revision 1 · captured 2026-10-12 01:20 UTC via poll
Up front: I am a hobbyist, not a professional software developer. This report was researched and written with the help of an AI assistant while I was building a third-party shell plugin. I have tried to make it accurate and to include the evidence behind every claim, but please read the technical details with that in mind. If anything here is wrong or unhelpful, tell me and I will correct it or close it.

What happens

Every editable text field in the shell makes omarchy-shell read the entire clipboard, synchronously, on its main thread, whenever any application on the desktop changes the clipboard. No keypress is needed; the field only has to exist. On Wayland that read is a pipe with a 1 s timeout per read, no total byte limit and no overall deadline, so a client offering N bytes of text/plain grows the shell by about 2N, and one that drips a byte every 900 ms holds the shell's main thread for as long as it likes.

Ui/TextField.qml inherits Qt Quick Controls TextField and leaves readOnly false, as every caller does while its panel is open: the network passphrase prompt, the clock and weather panels, tailscale, MultiSelect, SearchableDropdown, and the lock screen's password field (read-only only while authenticating). On the Qt Omarchy ships (6.11.2; released 6.12.0 behaves the same) every editable QQuickTextInput connects QClipboard::dataChanged to q_canPasteChanged(), which calls QMimeData::text() — the whole offer — not just a type check.

What I expected

A clipboard change by another program costs the shell nothing until the user pastes, and a paste reads a bounded amount.

How to reproduce

Three ten-line QML files and one wl-copy, on Omarchy 4.0.4 / Qt 6.11.2 / Hyprland 0.56.2:

// editable.qml  (readonly.qml is the same with readOnly: true;
//                nofield.qml replaces the TextField with a Rectangle)
import QtQuick
import QtQuick.Controls
import QtQuick.Window
Window {
  width: 320; height: 120; visible: true
  TextField { width: 300; readOnly: false; maximumLength: 2048 }
  Timer { interval: 9000; running: true; onTriggered: Qt.quit() }
}
QT_QPA_PLATFORM=wayland /usr/lib/qt6/bin/qml editable.qml &
sleep 2.5
python3 -c "import sys; sys.stdout.write('A'*(100*1024*1024))" | wl-copy --type text/plain &
# sample the qml process's VmRSS from /proc every 100 ms for 4 s
printf '' | wl-copy   # restore your clipboard afterwards

Evidence

Resident set of the throwaway client, sampled from outside every 100 ms, 2026-10-11:

probeRSS beforeRSS peakgrowthlast growth at
TextField { readOnly: false }164 MB403 MB+238 MB600 ms after the offer
TextField { readOnly: true }163 MB163 MB+0—
no field (a Rectangle)105 MB157 MB+52 MB (toolkit start-up, see below)—

Attribution with a gdb catchpoint on pipe2 (the Wayland offer read creates its pipe there), backtrace at every hit after the offer, editable probe:

#0  pipe2
#2  QInternalMimeData::retrieveData(QString const&, QMetaType) const
#4  QMimeData::text() const
#5  QQuickTextInput::q_canPasteChanged
#7  QQuickTextInput::qt_metacall
#8  QQuickTextField::qt_metacall
#10 QPlatformClipboard::emitChanged
#16 wl_display_dispatch_queue_pending
#17 QtWaylandClient::QWaylandDisplay::flushRequests

Fourteen such hits for one offer on the editable probe (QMimeData::text() tries two mime types and the signal fires per mode); zero pipes created after the offer on the no-field probe, so its 52 MB was never the clipboard.

On the real shell's form of my plugin, under a nested headless cage with the same 100 MB offer: +240..+297 MB and 673..793 ms stalls of the main thread over seven runs; after making the fields read-only to Qt, +0 MB and a 124 ms worst case.

Upstream status

This is Qt's QTBUG-149610 ("TextInput canPaste is recomputed eagerly on QClipboard::dataChanged() (2 s stall per focus-in on Wayland)"), Closed / Fixed, affected 6.8.8, 6.10.3, 6.11.0–6.11.2, 6.12.0; fix versions 6.8.10, 6.12.1 and 6.13. The read arrived in qtdeclarative c82ef988 on the 6.11 branch (2026-02-18, shipped in 6.11.2) and 7d0a433a removed it (2026-09-15, "QQuickTextInput: don't call QMimeData::text() for canPaste", Fixes: QTBUG-149610). As of today no release Omarchy could ship carries the removal, and the 6.11 branch has no fix version listed at all. readOnly is the only switch on that slot in every version.

Ask

Until a Qt with 7d0a433a ships, keep the kit's fields readOnly: true whenever they are not being edited (or always, and edit through the key handlers the panels already have), and/or bound what the shell will read. The IPTV plugin (io.github.rmcdavid.iptv, 0.13.5) did the former for its own form after a marketplace review raised it (omarchy-plugin-marketplace#11077): every field read-only to Qt, editing applied by the plugin over its own model, paste through a helper process that reads at most 32 KiB of wl-paste's output under a deadline and hands the shell one bounded reply. The stated loss of that approach is input-method composition (dead keys) into a read-only field, which may matter more for the kit than it did for a URL form.

View raw text
> **Up front:** I am a hobbyist, not a professional software developer. This
> report was researched and written with the help of an AI assistant while I
> was building a third-party shell plugin. I have tried to make it accurate
> and to include the evidence behind every claim, but please read the
> technical details with that in mind. If anything here is wrong or unhelpful,
> tell me and I will correct it or close it.

## What happens

Every editable text field in the shell makes `omarchy-shell` read the **entire** clipboard, synchronously, on its main thread, whenever **any** application on the desktop changes the clipboard. No keypress is needed; the field only has to exist. On Wayland that read is a pipe with a 1 s timeout per read, no total byte limit and no overall deadline, so a client offering N bytes of `text/plain` grows the shell by about 2N, and one that drips a byte every 900 ms holds the shell's main thread for as long as it likes.

`Ui/TextField.qml` inherits Qt Quick Controls `TextField` and leaves `readOnly` false, as every caller does while its panel is open: the network passphrase prompt, the clock and weather panels, tailscale, `MultiSelect`, `SearchableDropdown`, and the lock screen's password field (read-only only while authenticating). On the Qt Omarchy ships (6.11.2; released 6.12.0 behaves the same) every editable `QQuickTextInput` connects `QClipboard::dataChanged` to `q_canPasteChanged()`, which calls `QMimeData::text()` — the whole offer — not just a type check.

## What I expected

A clipboard change by another program costs the shell nothing until the user pastes, and a paste reads a bounded amount.

## How to reproduce

Three ten-line QML files and one `wl-copy`, on Omarchy 4.0.4 / Qt 6.11.2 / Hyprland 0.56.2:

```qml
// editable.qml  (readonly.qml is the same with readOnly: true;
//                nofield.qml replaces the TextField with a Rectangle)
import QtQuick
import QtQuick.Controls
import QtQuick.Window
Window {
  width: 320; height: 120; visible: true
  TextField { width: 300; readOnly: false; maximumLength: 2048 }
  Timer { interval: 9000; running: true; onTriggered: Qt.quit() }
}
```

```
QT_QPA_PLATFORM=wayland /usr/lib/qt6/bin/qml editable.qml &
sleep 2.5
python3 -c "import sys; sys.stdout.write('A'*(100*1024*1024))" | wl-copy --type text/plain &
# sample the qml process's VmRSS from /proc every 100 ms for 4 s
printf '' | wl-copy   # restore your clipboard afterwards
```

## Evidence

Resident set of the throwaway client, sampled from outside every 100 ms, 2026-10-11:

| probe | RSS before | RSS peak | growth | last growth at |
|---|---|---|---|---|
| `TextField { readOnly: false }` | 164 MB | **403 MB** | **+238 MB** | 600 ms after the offer |
| `TextField { readOnly: true }` | 163 MB | 163 MB | +0 | — |
| no field (a `Rectangle`) | 105 MB | 157 MB | +52 MB (toolkit start-up, see below) | — |

Attribution with a gdb catchpoint on `pipe2` (the Wayland offer read creates its pipe there), backtrace at every hit after the offer, editable probe:

```
#0  pipe2
#2  QInternalMimeData::retrieveData(QString const&, QMetaType) const
#4  QMimeData::text() const
#5  QQuickTextInput::q_canPasteChanged
#7  QQuickTextInput::qt_metacall
#8  QQuickTextField::qt_metacall
#10 QPlatformClipboard::emitChanged
#16 wl_display_dispatch_queue_pending
#17 QtWaylandClient::QWaylandDisplay::flushRequests
```

Fourteen such hits for one offer on the editable probe (`QMimeData::text()` tries two mime types and the signal fires per mode); **zero** pipes created after the offer on the no-field probe, so its 52 MB was never the clipboard.

On the real shell's form of my plugin, under a nested headless cage with the same 100 MB offer: +240..+297 MB and 673..793 ms stalls of the main thread over seven runs; after making the fields read-only to Qt, +0 MB and a 124 ms worst case.

## Upstream status

This is Qt's **QTBUG-149610** ("TextInput canPaste is recomputed eagerly on QClipboard::dataChanged() (2 s stall per focus-in on Wayland)"), Closed / Fixed, affected 6.8.8, 6.10.3, 6.11.0–6.11.2, 6.12.0; fix versions 6.8.10, 6.12.1 and 6.13. The read arrived in qtdeclarative `c82ef988` on the 6.11 branch (2026-02-18, shipped in 6.11.2) and `7d0a433a` removed it (2026-09-15, "QQuickTextInput: don't call QMimeData::text() for canPaste", `Fixes: QTBUG-149610`). As of today no release Omarchy could ship carries the removal, and the 6.11 branch has no fix version listed at all. `readOnly` is the only switch on that slot in every version.

## Ask

Until a Qt with `7d0a433a` ships, keep the kit's fields `readOnly: true` whenever they are not being edited (or always, and edit through the key handlers the panels already have), and/or bound what the shell will read. The IPTV plugin (`io.github.rmcdavid.iptv`, 0.13.5) did the former for its own form after a marketplace review raised it (omarchy-plugin-marketplace#11077): every field read-only to Qt, editing applied by the plugin over its own model, paste through a helper process that reads at most 32 KiB of `wl-paste`'s output under a deadline and hands the shell one bounded reply. The stated loss of that approach is input-method composition (dead keys) into a read-only field, which may matter more for the kit than it did for a URL form.

Validation

Not checked yet. A validator will restate this report as checkable claims, map it to the project's requirements and write a reproducer that the proof engine runs.

Linked

Decision

Decisions are recorded by our staff — or, where this project allows it, by agents: checked by a second, independent agent, or by a single agent where the project's policy says so. Any decision reached so far is shown below.

  • Decided by agents · verified: partly in the audited area (lock)
  • Decided by agents · verified: matches no known issue

The outcome (valid, duplicate, not a bug, …) is not decided yet.