Threat Model¶
Security analysis of the dotfiles distribution. Covers trust boundaries, threat actors, attack surfaces, and mitigations.
Trust Boundary¶
The primary trust boundary is the local machine. Dotfiles are deployed to and executed on the user's own system. All configuration files, scripts, and templates run with the user's privileges.
┌─────────────────────────────────────────────────┐
│ Local Machine (trusted zone) │
│ ┌─────────────────┐ ┌──────────────────────┐ │
│ │ ~/.dotfiles/ │ │ ~/.config/ (deployed)│ │
│ │ (source repo) │──│ Shell configs, nvim │ │
│ └─────────────────┘ └──────────────────────┘ │
│ │
│ ┌─────────────────┐ ┌──────────────────────┐ │
│ │ ~/.local/bin/ │ │ ~/.cache/shell/ │ │
│ │ (user scripts) │ │ (cached eval output) │ │
│ └─────────────────┘ └──────────────────────┘ │
└─────────────────────────────────────────────────┘
│
─────┼──────── Trust boundary ────────
│
┌─────────────────────────────────────────────────┐
│ External (untrusted zone) │
│ GitHub (repo hosting), Homebrew, Nix, │
│ Zinit plugins, Neovim plugins, npm, pip │
└─────────────────────────────────────────────────┘
Threat Actors¶
| Actor | Motivation | Capability |
|---|---|---|
| Supply chain attacker | Inject malicious code via dependency | Compromise upstream packages (Homebrew, npm, Zinit plugins) |
| Secrets harvester | Steal API keys, SSH keys, tokens | Scrape git history, shell history, env vars |
| Privilege escalation | Gain root access | Exploit sudo aliases, writable scripts in PATH |
| Network attacker | Intercept credentials | MITM on install scripts, curl-pipe-bash |
Attack Surfaces¶
1. Shell Startup Scripts¶
Risk: Malicious code in sourced files executes with user privileges on every shell start.
Mitigations:
- All shell scripts pass
shellcheck --severity=error set -euo pipefailenforced in all operational scriptsevalusage hardened with process substitution (. /dev/stdin)- Input validation on dynamic function generation
DOTFILES_ULTRA_FAST=1bypasses all non-core sourcing
2. Secrets Exposure¶
Risk: API keys, tokens, and SSH keys leaked via git history, shell history, or environment.
Mitigations:
- Gitleaks pre-commit hook blocks secrets in commits
- Atuin
history_filterexcludes sensitive patterns - Age encryption for local secret storage
dot secrets setuses secure prompts (no shell history).gitignoreexcludeskey.txt,.env, credential files
3. Supply Chain Dependencies¶
Risk: Compromised upstream packages injected into the toolchain.
Mitigations:
- Nix Flakes provide reproducible, pinned dependencies
- Zinit plugin versions pinned (
ver"0.8.0") - Neovim plugin versions locked via
lazy-lock.json install.shuses HTTPS for all downloads- Homebrew formula integrity via bottle checksums
4. Path Manipulation¶
Risk: Attacker places malicious binary in a PATH directory that shadows legitimate tools.
Mitigations:
- PATH construction is deterministic (template-generated)
~/.local/binis user-controlled and checked for writability- No world-writable directories in PATH
prependpathfunction validates directory existence
5. Template Injection¶
Risk: Chezmoi template variables could inject shell code if not properly quoted.
Mitigations:
- Template variables come from
.chezmoidata.toml(user-controlled) - No external/network data used in templates
- Template validation via
chezmoi apply --dry-runin CI
6. Cached Eval Files¶
Risk: Stale or tampered cache files in ~/.cache/shell/ sourced at startup.
Mitigations:
_cached_evalvalidates cache against binary mtime- Cache files are user-owned (0644)
- Cache directory is under
$XDG_CACHE_HOME(user-controlled) - Cache can be cleared with
rm -rf ~/.cache/shell/
Residual Risks¶
| Risk | Likelihood | Impact | Status |
|---|---|---|---|
| Zinit plugin compromise | Low | High | Mitigated by version pinning |
| Shell history leak | Medium | Medium | Mitigated by Atuin filter |
| Stale Nix closure | Low | Low | Accepted (manual nix flake update) |
| macOS Keychain access | Low | Medium | Accepted (OS-level protection) |
Recommendations¶
- Run
gitleaks detectbefore every push (pre-commit hook enforced) - Rotate secrets on a 90-day schedule
- Audit
lazy-lock.jsondiffs when updating Neovim plugins - Pin Homebrew versions for security-critical tools
- Use
DOTFILES_ULTRA_FAST=1in CI to minimize attack surface