# Risk map — ohmyzsh/ohmyzsh

> Canonical page: https://codevetter.com/unpack/ohmyzsh/risk-map

# Risk map — ohmyzsh/ohmyzsh

Scanned commit 86ef6555e068663736a33376e4055aca9c1acc89 (2026-09-22). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

The dominant risks are supply-chain and self-modification: every user runs curl|sh installer code and an auto-updater that git-pulls new shell code into a live config; `omz` commands rewrite the user's .zshrc with awk; and 368 community plugins execute unchecked code at every shell start. Mitigations exist (compfix permission checks, PR-test label gating, .zshrc backups + syntax validation, hardened CI), but coverage of the critical paths is minimal.
- The documented install path is `sh -c "$(curl -fsSL .../tools/install.sh)"` — remote code executed with user privileges; the script then chsh's the login shell (via sudo when available) and execs zsh. — [tools/install.sh#L1-8](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/tools/install.sh#L1-L8) [tools/install.sh#L497-504](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/tools/install.sh#L497-L504) [tools/install.sh#L601](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/tools/install.sh#L601)
- install.sh resolves $HOME via `eval echo ~"$USER"` when HOME is unset — an acknowledged CWE-78-adjacent path that is only safe because $USER is first restricted to [alnum, _, ., -]. — [tools/install.sh#L52-76](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/tools/install.sh#L52-L76)
- Auto-update executes freshly fetched code: upgrade.sh does `git pull --rebase` on master and the new oh-my-zsh.sh/plugins run at next shell start; the 'cooldown' zstyle exists specifically to delay applying new commits as a supply-chain buffer. — [tools/upgrade.sh#L259-265](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/tools/upgrade.sh#L259-L265) [tools/check_for_upgrade.sh#L74-88](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/tools/check_for_upgrade.sh#L74-L88) [README.md#L477-491](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/README.md#L477-L491)
- Every plugin file is arbitrary code sourced into every interactive shell; the only vetting is maintainer review, and `omz pr test` explicitly warns unlabeled PRs 'may contain malicious code' before fetching and running them. — [oh-my-zsh.sh#L235-239](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/oh-my-zsh.sh#L235-L239) [lib/cli.zsh#L652-666](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/lib/cli.zsh#L652-L666)
- omz plugin/theme commands write directly into ${ZDOTDIR:-$HOME}/.zshrc via awk transformations; mitigations are the .zshrc.bck backup and the post-write `zsh -n` syntax check with automatic rollback, but a semantically-wrong-but-parseable edit would stick. — [lib/cli.zsh#L297-315](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/lib/cli.zsh#L297-L315) [lib/cli.zsh#L832-856](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/lib/cli.zsh#L832-L856)
- compinit -i skips completion dirs that fail compaudit ownership/permission checks; users hitting this get a warning via handle_completion_insecurities — ZSH_DISABLE_COMPFIX=true bypasses the check entirely by switching to compinit -u. — [oh-my-zsh.sh#L153-164](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/oh-my-zsh.sh#L153-L164) [lib/compfix.zsh](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/lib/compfix.zsh)
- check_for_upgrade.sh's GitHub API call uses a 2s connect timeout and treats non-GitHub remotes as always-updateable; is_update_available returning 0 on merge-base failure assumes updates exist — fail-open rather than fail-closed. — [tools/check_for_upgrade.sh#L90-134](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/tools/check_for_upgrade.sh#L90-L134)
- uninstall.sh runs `rm -rf ~/.oh-my-zsh` and `chsh` after a single y/N prompt, and install.sh's setup_shell runs `sudo chsh` — destructive/account-level operations driven by tty prompts that are bypassed only in unattended mode. — [tools/uninstall.sh#L13-28](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/tools/uninstall.sh#L13-L28) [tools/install.sh#L497-512](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/tools/install.sh#L497-L512)
- update.lock is a stale-able mkdir lock under $ZSH/log: the code deletes locks older than a day, and the EXIT/INT/QUIT trap must return $ret correctly so Ctrl+C actually interrupts — a fragile bit of signal semantics the comments call out. — [tools/check_for_upgrade.sh#L209-235](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/tools/check_for_upgrade.sh#L209-L235)
- Async prompt handler cancellation kills the process group only under MONITOR; without job control it can only TERM the direct child, and the file itself notes forked grandchildren 'may be orphaned and left behind'. — [lib/async_prompt.zsh#L60-77](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/lib/async_prompt.zsh#L60-L77)
- lib/vcs_info.zsh exists specifically to %-quote hook_com fields before vcs_info hooks run — a workaround for CVE-2021-45444 where crafted branch/repo data could trigger command substitution in prompts on zsh 5.0.3-5.8. — [lib/vcs_info.zsh](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/lib/vcs_info.zsh)
- git.zsh documents real-world fragility: a =~ regex on non-UTF-8 git output aborted with REG_ILLSEQ (fixed via LC_ALL=C scoping), and async prompt is behind ':omz:alpha:lib:git' with 'force'/opt-out because of known issue reports; the CentOS-7 workaround carries a dated TODO. — [lib/git.zsh#L52-70](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/lib/git.zsh#L52-L70) [lib/git.zsh#L171-236](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/lib/git.zsh#L171-L236)
- SECURITY.md states only the latest master commit is supported and relies on 'automated updates to minimize the time between vulnerability publication and patch release' — there is no stable/release line to pin. — [SECURITY.md](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/SECURITY.md)
- The dependencies updater executes precopy/postcopy shell snippets declared in .github/dependencies.yml inside CI with a write-capable token — a code-execution path driven by YAML data. — [.github/dependencies.yml](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/.github/dependencies.yml) [.github/workflows/dependencies/updater.py](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/.github/workflows/dependencies/updater.py) [.github/workflows/dependencies.yml](https://github.com/ohmyzsh/ohmyzsh/blob/86ef6555e068663736a33376e4055aca9c1acc89/.github/workflows/dependencies.yml)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
