Merge upstream quattro (factory-reset hash scrub + hook/state path guards) - #25
cursor[bot] wants to merge 4 commits into
Conversation
omarchy-hook and omarchy-state set join a name straight into a path. A name with a slash, or a bare . or .., points outside the hooks or state directory. Every caller in the repo passes a fixed label, so this is a footgun guard for future callers, not a fix for anything that ships today. Names with dots in the middle (a..b) stay allowed. omarchy-state clear is untouched: find -name matches basenames only. (cherry picked from commit 0a65b45)
(cherry picked from commit a75924a)
userdel rewrites /etc/subuid and /etc/subgid, and like every shadow-utils database write it leaves the previous contents behind in a dash-suffixed backup. The scrub removed four of the six backups those tools produce, so the retained @factory baseline still named the previous owner in /etc/subuid- and /etc/subgid- along with their subordinate ID range. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> (cherry picked from commit a00be8f)
The runner already rejects a slash, a bare . or .. The installer still joined the type into hooks/<type>.d before mkdir/cp, so a name nothing can run could still land on disk. (cherry picked from commit e522a18)
|
Important Review skippedBot user detected. To trigger a single review, invoke the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Advanced Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
| users=$(awk -F: '$3 >= 1000 && $3 < 60000 { print $1 }' "$root/etc/passwd") || return 1 | ||
| for user in $users; do | ||
| userdel --root "$root" "$user" 2>>"$LOG_FILE" || return 1 | ||
| rm -rf "${root:?}/home/$user" || return 1 |
There was a problem hiding this comment.
🔒 Agentic Security Review
Severity: MEDIUM
scrub_factory_accounts reads uid 1000–59999 logins from $root/etc/passwd and, after userdel --root succeeds, runs rm -rf "${root}/home/$user" as root. Those names are not limited to a single path component (no /, not . or ..), unlike the hook/state name guards in this PR.
userdel --root can accept a login such as ../../OUTSIDE. The rm -rf is evaluated on the host, not inside the snapshot, so the path can leave $root. On the production layout ($TOP_MNT/@factory or $TOP_MNT/@omarchy-reset-next), that can resolve to live host paths.
Impact: A previous owner who can plant a nonstandard passwd entry in the factory snapshot can make factory reset delete files outside the snapshot while running as root.
Reviewed by Cursor Security Reviewer for commit 85cca3d. Configure here.
|
Closing as superseded. The leftover from this sync already landed on quattro via #37. |




Merges 2 new first-parent commits (4 cherry-picked non-merge commits) from omacom/omarchy
quattrosince last night's check (2fbac0c8/ PR #23). Upstream HEAD is now9c5482c5(upstream #8170, merged 2026-09-16).This is everything new since the 2026-09-15 cron. Leftover #18 already landed this morning as PR #24. Fork-only Cursor work is untouched: official-tarball installer, no mise wrapper, usage collector, and the theme-set fix from #22.
Factory reset now actually erases old hashes (upstream omacom#10379, fixes omacom#10378)
passwd --lockleft the previous root hash in@factory/etc/shadowand the dash-suffixed backups, so the next owner could recover itscrub_factory_accountsnow runs on both the staged reset root and the retained@factorybaseline:userdeluid≥1000 accounts, set root's password field to!, then delete the shadow-utils backupssubuid-/subgid-(userdel left the previous owner's subordinate ID range in those backups)@factoryback to read-onlyHook and state names cannot be paths (upstream omacom#8170)
omarchy-hook,omarchy-hook-install, andomarchy-state setnow refuse an empty name, a name with/, or a name that is exactly.or..(exit 2)omarchy-hook ../../evilfrom running~/.config/evilandomarchy-state set ../../escapefrom creating~/.local/escapeomarchy-hook-installgot the same guard so a slashed type cannotmkdir/cpunderhooks/<type>.dbefore the runner would refuse ita..b) stay allowed.omarchy-state clearis unchanged:find -namematches basenames onlyTests
Focused suites passed:
hook-state-name-guard-test.sh(19 cases),factory-reset-accounts-test.sh(both roots, repeat reset, six injected cleanup failures; ran via user namespace), and./test/cli(metadata unchanged).Note
High Risk
Changes factory-reset account and shadow handling on sale/handoff paths and hardens CLI utilities that write or execute under user config/state directories.
Overview
Merges upstream factory-reset credential scrubbing and hook/state path guards, with focused shell tests.
Factory reset no longer relies on
passwd --lock, which left recoverable hashes in@factoryand dash-suffixed shadow backups. A sharedscrub_factory_accountsremoves uid≥1000 users and homes, sets root’s password field to!viausermod, and deletespasswd-/shadow-/subuid-/subgid-backups on both the staged reset root and the retained@factorybaseline. Cleanup failures abort the reset (baseline is re-marked read-only on scrub failure). Tests cover normal/locked root, repeat reset, and injecteduserdel/usermod/rmfailures.omarchy-hook,omarchy-hook-install, andomarchy-state setnow reject empty names, names containing/, or names exactly.or..(exit 2), blocking path-style escape while still allowing dotted labels likea..b.omarchy-state clearis unchanged. New tests exercise valid names, traversal attempts, and install-sidemkdir/cpguards.Reviewed by Cursor Bugbot for commit 85cca3d. Configure here.