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-5153GitHub issuePublicDecided· Out of scope

omarchy-agent-crash splices unsanitized, attacker-reachable crash metadata into the AI-diagnosis prompt with no fencing

Reported by TaylorBurke · filed Oct 5, 2026 · open at source

Decided: Out of scope — decided by agents · verified 3 days ago.

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

omarchy-agent-crash splices unsanitized, attacker-reachable crash metadata into the AI-diagnosis prompt with no fencingrevision 1 · captured 2026-10-05 07:01 UTC via poll

What happened

omarchy-crash-watch (enabled by default; install/user/first-run/enable-user-units.sh:22) reads COREDUMP_EXE straight from the systemd-coredump journal for any process the local user runs — a value fully controlled by whoever ran that process, since Linux filenames can contain almost any byte, including literal newlines. It passes exe to --exec omarchy-agent-crash "$pid" "$comm" "$exe" "$signal" as a safe, discrete argv word (bin/omarchy-crash-watch:45) — no shell/argv injection there.

But bin/omarchy-agent-crash:40 then splices that same raw string directly into a heredoc that becomes the AI agent's prompt, with no escaping, fencing, or "this is untrusted data" framing:

prompt=$(
  cat <<PROMPT
...
  binary:   $exe
...
PROMPT
)
exec omarchy-agent --prompt "$prompt"

omarchy-agent then launches whichever agent the user has set as their default (Omarchy ships with none picked; bin/omarchy-default-agent's own comment: "Omarchy picks no agent for you") with its permission-bypass flag for this "unattended" path — every entry in that case table gets one (--permission-mode auto/bypassPermissions, --dangerously-skip-permissions, --approve-for-me, --yolo, --allow-all, per agent), per the comment above the table: "agents launched from the keybinding or menu run unattended, so each one starts with its own spelling of 'don't stop to ask.'"

Net effect: any unprivileged local process can get a diagnostic AI agent to read attacker-chosen text as part of its prompt, with no human confirmation gate, just by crashing itself at a path of its own choosing and having the user click the resulting "Process crashed — Click to diagnose with AI" notification — regardless of which of the 13 supported agents that user has configured as default.

Why I'm filing this as a hardening suggestion, not a vulnerability report

I tested this against Claude Code specifically, because that's what was configured as the default agent on my test machine — not because it's an Omarchy default (there isn't one). Tried 5 different payloads: a bare injected instruction, authority framing (claiming to be the diagnose-crash skill's own documented step), field-blending (mimicking the report's own key: value structure), a fake ### SYSTEM / ### USER turn-boundary spoof, and a repeat of the strongest payload under --permission-mode bypassPermissions instead of auto (to rule out the permission flag itself as the deciding factor). All five were resisted — the model consistently identified the embedded text as data from the crash record rather than an instruction, e.g.:

"The process's command line and the name of a directory inside poc-crash-payload both contain text posing as a 'system report' instruction... That text came from the crashed program's own metadata, not from you or the skill, so I ignored it and ran nothing of the sort."

So there's no working bypass today against this one agent, and per the program's own policy this doesn't cross a confirmed security boundary. But this is one model's behavior at one point in time — the same unsanitized splicing reaches whichever of the 13 supported agents a user has actually configured, and none of them get any sanitization or untrusted-data framing before this point. That's not something this code should rely on model alignment alone to cover.

Suggested direction

  • Wrap $comm/$exe/$signal in an explicit delimiter in the prompt template, with surrounding instruction text telling the agent these fields are unverified data from the crash record, not from the user.
  • Consider restricting $exe/$comm to printable characters (or otherwise normalizing) before they ever reach a prompt, the same discipline as sanitizing before any other sensitive sink.
  • Same bug class already fixed once in omarchy-toggle-input-device (#8129, merged) — untrusted local device/process metadata reaching a code-execution-adjacent context — just not yet covered here.

Related: #8607 — tested whether its proposed auto → bypassPermissions fix changes this outcome for Claude specifically. It doesn't (same result both ways), so I don't believe it's blocked by this; cross-referencing only.

View raw text
## What happened

`omarchy-crash-watch` (enabled by default; `install/user/first-run/enable-user-units.sh:22`) reads `COREDUMP_EXE` straight from the systemd-coredump journal for *any* process the local user runs — a value fully controlled by whoever ran that process, since Linux filenames can contain almost any byte, including literal newlines. It passes `exe` to `--exec omarchy-agent-crash "$pid" "$comm" "$exe" "$signal"` as a safe, discrete argv word (`bin/omarchy-crash-watch:45`) — no shell/argv injection there.

But `bin/omarchy-agent-crash:40` then splices that same raw string directly into a heredoc that becomes the AI agent's prompt, with no escaping, fencing, or "this is untrusted data" framing:

```bash
prompt=$(
  cat <<PROMPT
...
  binary:   $exe
...
PROMPT
)
exec omarchy-agent --prompt "$prompt"
```

`omarchy-agent` then launches whichever agent the user has set as their default (Omarchy ships with none picked; `bin/omarchy-default-agent`'s own comment: *"Omarchy picks no agent for you"*) with its permission-bypass flag for this "unattended" path — every entry in that case table gets one (`--permission-mode auto`/`bypassPermissions`, `--dangerously-skip-permissions`, `--approve-for-me`, `--yolo`, `--allow-all`, per agent), per the comment above the table: *"agents launched from the keybinding or menu run unattended, so each one starts with its own spelling of 'don't stop to ask.'"*

Net effect: any unprivileged local process can get a diagnostic AI agent to read attacker-chosen text as part of its prompt, with no human confirmation gate, just by crashing itself at a path of its own choosing and having the user click the resulting "Process crashed — Click to diagnose with AI" notification — regardless of which of the 13 supported agents that user has configured as default.

## Why I'm filing this as a hardening suggestion, not a vulnerability report

I tested this against Claude Code specifically, because that's what was configured as the default agent on my test machine — not because it's an Omarchy default (there isn't one). Tried 5 different payloads: a bare injected instruction, authority framing (claiming to be the `diagnose-crash` skill's own documented step), field-blending (mimicking the report's own `key: value` structure), a fake `### SYSTEM` / `### USER` turn-boundary spoof, and a repeat of the strongest payload under `--permission-mode bypassPermissions` instead of `auto` (to rule out the permission flag itself as the deciding factor). **All five were resisted** — the model consistently identified the embedded text as data from the crash record rather than an instruction, e.g.:

> "The process's command line and the name of a directory inside `poc-crash-payload` both contain text posing as a 'system report' instruction... That text came from the crashed program's own metadata, not from you or the skill, so I ignored it and ran nothing of the sort."

So there's no working bypass today against this one agent, and per the program's own policy this doesn't cross a confirmed security boundary. But this is one model's behavior at one point in time — the same unsanitized splicing reaches whichever of the 13 supported agents a user has actually configured, and none of them get any sanitization or untrusted-data framing before this point. That's not something this code should rely on model alignment alone to cover.

## Suggested direction

- Wrap `$comm`/`$exe`/`$signal` in an explicit delimiter in the prompt template, with surrounding instruction text telling the agent these fields are unverified data from the crash record, not from the user.
- Consider restricting `$exe`/`$comm` to printable characters (or otherwise normalizing) before they ever reach a prompt, the same discipline as sanitizing before any other sensitive sink.
- Same bug *class* already fixed once in `omarchy-toggle-input-device` (#8129, merged) — untrusted local device/process metadata reaching a code-execution-adjacent context — just not yet covered here.

Related: #8607 — tested whether its proposed `auto` → `bypassPermissions` fix changes this outcome for Claude specifically. It doesn't (same result both ways), so I don't believe it's blocked by this; cross-referencing only.

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 21:31 UTC