Proof Portal
Omarchy
ProbeLabs65 findings · 95 requirementsA 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.
Third-party plugin services can't resolve their own install directory (manifest.__sourceDir is stripped)
Reported by alvarobolanos · filed Sep 18, 2026Closed upstream on 2026-10-03 by the merge of PR #11925 (closed by spencerbull). GitHub close reason: completed.
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?
- Not yet mapped to any requirement or component.
- 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. No decision has been recorded yet.
Original report
Description
shell.qml's publicPluginManifest() strips __sourceDir (along with __isFirstParty and __hostCapabilities) from the manifest handed to third-party plugin entry points:
function publicPluginManifest(manifest) {
if (!manifest) return null
if (manifest.__isFirstParty) return manifest
var copy = JSON.parse(JSON.stringify(manifest))
delete copy.__sourceDir
delete copy.__isFirstParty
delete copy.__hostCapabilities
return copy
}This isn't limited to service entry points. The same stripped manifest is assigned identically at three call sites:
- ensureService(), line 930 — inst.manifest = shell.publicPluginManifest(manifest)
- configureBar(), line 222 — for a third-party kind: "bar" replacement
- the panel-entry Instantiator delegate, line 1343 — any third-party plugin's panel entry point
Any third-party plugin relying on manifest.__sourceDir in any of these three contexts to locate its own bundled scripts/assets gets an empty string back, with no error surfaced anywhere — Quickshell.Io.Process just silently fails to start (Process failed to start, likely because the binary could not be found) because the computed command path collapses to something like /scripts/foo.sh instead of /home/user/.config/omarchy/plugins/<id>/scripts/foo.sh. (Bar-widget entries are unaffected — syncPluginWidgets() builds a separate sourceDir from the raw, unstripped manifest before this stripping happens.)
Concrete repro (omamail plugin)
The omamail community plugin (Gmail/HEY/IMAP client) computes its plugin directory in Service.qml as:
readonly property string pluginDir: manifest && manifest.__sourceDir
? String(manifest.__sourceDir) : ""Because __sourceDir is always stripped for this third-party plugin, pluginDir is always "". Every helper script it shells out to (pkce.sh for the OAuth PKCE challenge, the socat-based OAuth callback listener setup, config-store.sh, keyring-store.sh, mail-transport.sh, contact-suggestions.py) fails to launch. In practice this means clicking "Sign in with Google..." does nothing at all — no error dialog, no browser tab, nothing — because the very first script in the flow (pkce.sh) never starts. The only visible evidence is in the shell's own journal log:
WARN: Process failed to start, likely because the binary could not be found. Command: QList("/scripts/pkce.sh")This is fully deterministic — it happens on every attempt, survives plugin disable/enable, a forced rescanPlugins, and a full omarchy restart shell, because none of those change what shell.qml strips. omamail's panel entry point (App.qml) is a third-party plugin panel too, so it's a second, independent instance of the same class of bug within one plugin.
Expected behavior
A third-party plugin's own install directory isn't sensitive information relative to that plugin itself — it already knows its own id (which is not stripped) and already reads/writes files under ~/.config/omarchy/plugins/<id>/ via its manifest-declared scripts. Stripping __sourceDir provides no real isolation, since the same path is trivially reconstructible from id plus the fixed, well-known third-party plugins directory — which is exactly the workaround below. __isFirstParty and __hostCapabilities look like the fields that actually matter for privilege signaling; __sourceDir looks like it was swept up in the same delete unintentionally. Fixing publicPluginManifest() to retain it would resolve all three call sites (service, bar, panel) at once, so a fix and its regression test should cover all three, not just ensureService().
Workaround applied locally
Patched the affected plugin's own Service.qml to fall back to reconstructing the path when __sourceDir is absent:
readonly property string pluginDir: manifest && manifest.__sourceDir
? String(manifest.__sourceDir)
: (Quickshell.env("HOME") + "/.config/omarchy/plugins/" + pluginId)This works, but it's fragile — it will be silently overwritten by the next omarchy plugin update, and every third-party plugin author would have to independently discover and apply the same workaround for each entry point they use.
Environment
- Omarchy version: 4.0.4-1
uname -r: 7.2.5-3-omarchy
View raw text
### Description
`shell.qml`'s `publicPluginManifest()` strips `__sourceDir` (along with `__isFirstParty` and `__hostCapabilities`) from the manifest handed to third-party plugin entry points:
```qml
function publicPluginManifest(manifest) {
if (!manifest) return null
if (manifest.__isFirstParty) return manifest
var copy = JSON.parse(JSON.stringify(manifest))
delete copy.__sourceDir
delete copy.__isFirstParty
delete copy.__hostCapabilities
return copy
}
```
This isn't limited to `service` entry points. The same stripped manifest is assigned identically at three call sites:
- `ensureService()`, line 930 — `inst.manifest = shell.publicPluginManifest(manifest)`
- `configureBar()`, line 222 — for a third-party `kind: "bar"` replacement
- the panel-entry `Instantiator` delegate, line 1343 — any third-party plugin's `panel` entry point
Any third-party plugin relying on `manifest.__sourceDir` in *any* of these three contexts to locate its own bundled scripts/assets gets an empty string back, with no error surfaced anywhere — `Quickshell.Io.Process` just silently fails to start (`Process failed to start, likely because the binary could not be found`) because the computed command path collapses to something like `/scripts/foo.sh` instead of `/home/user/.config/omarchy/plugins/<id>/scripts/foo.sh`. (Bar-*widget* entries are unaffected — `syncPluginWidgets()` builds a separate `sourceDir` from the raw, unstripped manifest before this stripping happens.)
### Concrete repro (omamail plugin)
The `omamail` community plugin (Gmail/HEY/IMAP client) computes its plugin directory in `Service.qml` as:
```qml
readonly property string pluginDir: manifest && manifest.__sourceDir
? String(manifest.__sourceDir) : ""
```
Because `__sourceDir` is always stripped for this third-party plugin, `pluginDir` is always `""`. Every helper script it shells out to (`pkce.sh` for the OAuth PKCE challenge, the `socat`-based OAuth callback listener setup, `config-store.sh`, `keyring-store.sh`, `mail-transport.sh`, `contact-suggestions.py`) fails to launch. In practice this means clicking "Sign in with Google..." does nothing at all — no error dialog, no browser tab, nothing — because the very first script in the flow (`pkce.sh`) never starts. The only visible evidence is in the shell's own journal log:
```
WARN: Process failed to start, likely because the binary could not be found. Command: QList("/scripts/pkce.sh")
```
This is fully deterministic — it happens on every attempt, survives plugin disable/enable, a forced `rescanPlugins`, and a full `omarchy restart shell`, because none of those change what `shell.qml` strips. omamail's `panel` entry point (`App.qml`) is a third-party plugin panel too, so it's a second, independent instance of the same class of bug within one plugin.
### Expected behavior
A third-party plugin's own install directory isn't sensitive information relative to that plugin itself — it already knows its own `id` (which is *not* stripped) and already reads/writes files under `~/.config/omarchy/plugins/<id>/` via its manifest-declared scripts. Stripping `__sourceDir` provides no real isolation, since the same path is trivially reconstructible from `id` plus the fixed, well-known third-party plugins directory — which is exactly the workaround below. `__isFirstParty` and `__hostCapabilities` look like the fields that actually matter for privilege signaling; `__sourceDir` looks like it was swept up in the same `delete` unintentionally. Fixing `publicPluginManifest()` to retain it would resolve all three call sites (service, bar, panel) at once, so a fix and its regression test should cover all three, not just `ensureService()`.
### Workaround applied locally
Patched the affected plugin's own `Service.qml` to fall back to reconstructing the path when `__sourceDir` is absent:
```qml
readonly property string pluginDir: manifest && manifest.__sourceDir
? String(manifest.__sourceDir)
: (Quickshell.env("HOME") + "/.config/omarchy/plugins/" + pluginId)
```
This works, but it's fragile — it will be silently overwritten by the next `omarchy plugin update`, and every third-party plugin author would have to independently discover and apply the same workaround for each entry point they use.
### Environment
- Omarchy version: 4.0.4-1
- `uname -r`: 7.2.5-3-omarchy
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
Not linked to any known issue, other report or change yet.
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.
No decision has been recorded yet.