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.
shell.json can be created 0644 and keeps that mode, exposing plugin secrets to other local users
Reported by rmcdavid · filed Oct 9, 2026 · open at source
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?
- AreaOutside the audited area· 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?
- Decided by agents and verified by a second, independent agent — see the decision.
Original report
Reporting this as a courtesy rather than as a complaint: shell.json holds
plugin settings, those settings can contain secrets, and the file can arrive
world-readable and stay that way.
Measured on Omarchy 4.0.4-1, Quickshell shell at /usr/share/omarchy/shell.
1. The packaged default is 0644.
$ stat -c '%a %n' /usr/share/omarchy/config/omarchy/shell.json
644 /usr/share/omarchy/config/omarchy/shell.json2. `omarchy-refresh-config` copies it with `cp -f`, so a file that does not
yet exist is created under the caller's umask. Reproduced against the real
source into a scratch directory:
cp under umask 022 -> 644
cp under umask 077 -> 600A copy onto an existing file keeps that file's mode, which is why a machine
that once had 0600 keeps it.
3. The shell's own writer preserves whatever mode the file already has.shell.qml:138 uses FileView { atomicWrites: true }. A purpose-built probe,
one FileView writing one scratch file, run twice:
| mode before the write | after |
|---|---|
| 0644 | 0644 |
| 0600 | 0600 |
The content changed both times, so the write happened. The atomic rename
neither resets the mode to the writer's umask nor tightens it.
Why it matters. ~/.config and ~/.config/omarchy are 0755 by default, so
only the home directory's mode stands between the file and other local users,
and 0755 homes are common. Plugin settings in that file routinely include URLs,
and for IPTV-style plugins a playlist URL carries the provider username and
password, either as userinfo or as query parameters. On a machine whereshell.json landed at 0644, those are readable by any other local account.
What would fix it upstream, either one:
- ship
config/omarchy/shell.jsonas 0600, and haveomarchy-refresh-config
create the user copy with that mode rather than inheriting the umask; or
- have the shell's writer enforce 0600 on the user config when it saves, since
it already owns that file's lifecycle.
The first is a one-line packaging change and covers fresh installs; the second
also repairs machines that already have 0644.
Heads-up, so it is not a surprise. The IPTV plugin
(io.github.rmcdavid.iptv) will tighten ~/.config/omarchy/shell.json to 0600
before it writes a provider URL into it, and refuse to save the source if it
cannot. It changes nothing else: not the directories, not the contents, not any
other file. If upstream adopts either fix above, that behaviour becomes a
no-op, which is the outcome we would prefer.
Happy to send a patch for whichever approach you favour.
View raw text
Reporting this as a courtesy rather than as a complaint: `shell.json` holds
plugin settings, those settings can contain secrets, and the file can arrive
world-readable and stay that way.
Measured on Omarchy 4.0.4-1, Quickshell shell at `/usr/share/omarchy/shell`.
**1. The packaged default is 0644.**
```
$ stat -c '%a %n' /usr/share/omarchy/config/omarchy/shell.json
644 /usr/share/omarchy/config/omarchy/shell.json
```
**2. `omarchy-refresh-config` copies it with `cp -f`**, so a file that does not
yet exist is created under the caller's umask. Reproduced against the real
source into a scratch directory:
```
cp under umask 022 -> 644
cp under umask 077 -> 600
```
A copy onto an *existing* file keeps that file's mode, which is why a machine
that once had 0600 keeps it.
**3. The shell's own writer preserves whatever mode the file already has.**
`shell.qml:138` uses `FileView { atomicWrites: true }`. A purpose-built probe,
one `FileView` writing one scratch file, run twice:
| mode before the write | after |
|---|---|
| 0644 | 0644 |
| 0600 | 0600 |
The content changed both times, so the write happened. The atomic rename
neither resets the mode to the writer's umask nor tightens it.
**Why it matters.** `~/.config` and `~/.config/omarchy` are 0755 by default, so
only the home directory's mode stands between the file and other local users,
and 0755 homes are common. Plugin settings in that file routinely include URLs,
and for IPTV-style plugins a playlist URL carries the provider username and
password, either as userinfo or as query parameters. On a machine where
`shell.json` landed at 0644, those are readable by any other local account.
**What would fix it upstream**, either one:
- ship `config/omarchy/shell.json` as 0600, and have `omarchy-refresh-config`
create the user copy with that mode rather than inheriting the umask; or
- have the shell's writer enforce 0600 on the user config when it saves, since
it already owns that file's lifecycle.
The first is a one-line packaging change and covers fresh installs; the second
also repairs machines that already have 0644.
**Heads-up, so it is not a surprise.** The IPTV plugin
(`io.github.rmcdavid.iptv`) will tighten `~/.config/omarchy/shell.json` to 0600
before it writes a provider URL into it, and refuse to save the source if it
cannot. It changes nothing else: not the directories, not the contents, not any
other file. If upstream adopts either fix above, that behaviour becomes a
no-op, which is the outcome we would prefer.
Happy to send a patch for whichever approach you favour.
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.
- Out of scopeDecided by agents · verified · 2026-10-09 23:51 UTC