ADR-003: Security-First Approach¶
Status: Accepted Date: 2026-02-09 Authors: @sebastienrousseau
Context¶
Dotfiles repositories present unique security challenges:
- They configure system behavior and permissions
- They may contain or reference secrets (API keys, tokens)
- They execute scripts with user privileges
- They're often cloned to multiple machines
A security breach in dotfiles can compromise all systems using them.
Decision¶
Implement a defense-in-depth security model with multiple layers:
Layer 1: Secrets Protection¶
Never commit secrets:
# .gitleaks.toml - block common secret patterns
[[rules]]
id = "generic-api-key"
regex = '''(?i)(api[_-]?key|apikey)\s*[:=]\s*['"]?([a-zA-Z0-9]{20,})'''
Encrypted secrets with age:
# Secrets stored encrypted, decrypted at apply time
chezmoi.encryption = "age"
chezmoi.age.identity = "~/.config/chezmoi/key.txt"
CI enforcement:
- Gitleaks runs on every PR
- TruffleHog for verified secrets detection
- Block merge if secrets detected
Layer 2: Input Validation¶
Path traversal prevention:
# Validate all user inputs
if [[ ! "$template_lang" =~ ^[a-zA-Z0-9_-]+$ ]]; then
die "Invalid template name: $template_lang"
fi
Safe file operations:
# Use absolute paths, validate before operations
local real_path
real_path="$(realpath -m "$user_input")"
if [[ "$real_path" != "$allowed_base"/* ]]; then
die "Path outside allowed directory"
fi
Layer 3: Opt-in System Modifications¶
Dangerous operations require explicit consent:
# Security scripts are opt-in
if [ "${DOTFILES_SECURITY:-0}" != "1" ]; then
echo "Security hardening is opt-in. Set DOTFILES_SECURITY=1 to enable."
exit 0
fi
Comprehensive logging:
# All system modifications logged
log_security_change() {
echo "[$(date -Iseconds)] $1" >> "$HOME/.local/share/dotfiles-security.log"
}
Layer 4: CI Security Scanning¶
Multi-tool approach:
- Gitleaks: Secrets in git history
- Shellcheck: Shell script vulnerabilities
- Checkov: Infrastructure misconfigurations
- Trivy: Container vulnerabilities (when applicable)
- CodeQL: Static analysis for Python/JavaScript
Weekly deep scans:
Layer 5: Minimal Privileges¶
Scripts request only needed permissions:
# Don't run as root unless necessary
if [ "$(id -u)" = "0" ]; then
die "This script should not run as root"
fi
# Use sudo only for specific commands
sudo sysctl -w net.ipv4.tcp_keepalive_time=60
Consequences¶
Positive¶
- Secrets never enter git history
- System modifications are auditable
- Multiple layers catch different vulnerability types
- Contributors have clear security patterns to follow
Negative¶
- Additional complexity in scripts
- Encrypted secrets require key management
- Some features disabled by default (friction)
Neutral¶
- Security vs convenience trade-offs explicit
- Regular security audits via scheduled CI
Security Checklist for Contributors¶
- [ ] No hardcoded secrets (use environment variables or age encryption)
- [ ] Validate all user inputs
- [ ] Use absolute paths for file operations
- [ ] Document any system modifications
- [ ] Test scripts with shellcheck
- [ ] Add appropriate permission checks