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.
Variable scoping bug in claim_path() inside omarchy-tailscale-receive
Reported by techaeris · filed Aug 27, 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
System details
Dell XPS 16, Omarchy Quattro Intel Ultra X7 358H Intel Arc B390
What's wrong?
- File:
/usr/bin/omarchy-tailscale-receive - Line: 30
- Function:
claim_path()
1. The Issue
In the function claim_path(), local variables are declared and initialized as follows:
claim_path() {
local staged="$1" name="${staged##*/}" base ext candidate index=0
...
}In Bash, declaring and assigning multiple local variables within a single local statement processes sequentially, but the local bindings are not completely in effect for subsequent assignments in the same command.
Therefore, when the expression name="${staged##*/}" is evaluated, the variable staged is not yet bound to the local variable staged="$1". Instead, Bash evaluates the expression using whichever value of staged is currently in the parent/caller's scope, or leaves it empty if no such variable exists.
2. Why It Currently Works (and Why It Is Fragile)
Currently, claim_path() is called inside deliver() as follows:
deliver() {
local staged target
while IFS= read -r staged; do
target=$(claim_path "$staged") || continue
...
done < <(find "$staging" -mindepth 1 -maxdepth 1)
}Because of Bash's dynamic scoping:
1. deliver() declares a local variable named staged and assigns it a file path in the while loop.
2. claim_path() is called.
3. Inside claim_path(), the statement local staged="$1" name="${staged##*/}" is evaluated.
4. Since staged is not yet bound locally during the evaluation of name, Bash looks up staged in the parent scope.
5. It finds staged in deliver()'s scope, which has the exact same value as $1 passed to claim_path().
6. Thus, name gets assigned the correct value by sheer coincidence of parent variable name collision.
If claim_path() is ever called from any other context (e.g., where the caller's variable is not named staged, or has a different value), name will be incorrectly initialized to empty or to the wrong path.
3. Proof of Concept & Reproduction
You can verify this behavior with these simple Bash test cases:
Test Case 1: Parent scope variable does not exist (Result is empty)
$ bash -c `f() { local a="foo" b="${a##*/}"; echo "a: $a, b: $b"; }; f`
a: foo, b: Test Case 2: Parent scope variable exists (Result resolves to parent value)
$ bash -c `f() { a="parent"; local a="foo" b="${a##*/}"; echo "a: $a, b: $b"; }; f`
a: foo, b: parent4. Proposed Fix
To resolve this scoping dependency and make the function robust and self-contained, split the local declaration so that staged is bound first:
claim_path() {
local staged="$1"
local name="${staged##*/}" base ext candidate index=0
...
}View raw text
### System details
Dell XPS 16, Omarchy Quattro Intel Ultra X7 358H Intel Arc B390
### What's wrong?
* **File:** `/usr/bin/omarchy-tailscale-receive`
* **Line:** 30
* **Function:** `claim_path()`
## 1. The Issue
In the function `claim_path()`, local variables are declared and initialized as follows:
```bash
claim_path() {
local staged="$1" name="${staged##*/}" base ext candidate index=0
...
}
```
In Bash, declaring and assigning multiple local variables within a single `local` statement processes sequentially, but the local bindings are not completely in effect for subsequent assignments in the same command.
Therefore, when the expression `name="${staged##*/}"` is evaluated, the variable `staged` is **not** yet bound to the local variable `staged="$1"`. Instead, Bash evaluates the expression using whichever value of `staged` is currently in the parent/caller's scope, or leaves it empty if no such variable exists.
## 2. Why It Currently Works (and Why It Is Fragile)
Currently, `claim_path()` is called inside `deliver()` as follows:
```bash
deliver() {
local staged target
while IFS= read -r staged; do
target=$(claim_path "$staged") || continue
...
done < <(find "$staging" -mindepth 1 -maxdepth 1)
}
```
Because of Bash's dynamic scoping:
1. `deliver()` declares a local variable named `staged` and assigns it a file path in the `while` loop.
2. `claim_path()` is called.
3. Inside `claim_path()`, the statement `local staged="$1" name="${staged##*/}"` is evaluated.
4. Since `staged` is not yet bound locally during the evaluation of `name`, Bash looks up `staged` in the parent scope.
5. It finds `staged` in `deliver()'s` scope, which has the **exact same value** as `$1` passed to `claim_path()`.
6. Thus, `name` gets assigned the correct value by sheer coincidence of parent variable name collision.
If `claim_path()` is ever called from any other context (e.g., where the caller's variable is not named `staged`, or has a different value), `name` will be incorrectly initialized to empty or to the wrong path.
## 3. Proof of Concept & Reproduction
You can verify this behavior with these simple Bash test cases:
### Test Case 1: Parent scope variable does not exist (Result is empty)
```bash
$ bash -c `f() { local a="foo" b="${a##*/}"; echo "a: $a, b: $b"; }; f`
a: foo, b:
```
### Test Case 2: Parent scope variable exists (Result resolves to parent value)
```bash
$ bash -c `f() { a="parent"; local a="foo" b="${a##*/}"; echo "a: $a, b: $b"; }; f`
a: foo, b: parent
```
## 4. Proposed Fix
To resolve this scoping dependency and make the function robust and self-contained, split the `local` declaration so that `staged` is bound first:
```bash
claim_path() {
local staged="$1"
local name="${staged##*/}" base ext candidate index=0
...
}
```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 09:28 UTC