2026-01-27 10:22:07 +08:00
# Mole Security Reference
2025-12-11 15:10:49 +08:00
2026-01-27 10:22:07 +08:00
Version 1.23.2 | 2026-01-26
2025-12-11 15:19:26 +08:00
2026-01-27 10:22:07 +08:00
## Recent Fixes
2025-12-11 15:18:04 +08:00
2026-01-27 10:22:07 +08:00
**Uninstall audit, Jan 2026:**
2025-12-11 15:18:04 +08:00
2026-01-27 10:22:07 +08:00
- `stop_launch_services()` now checks bundle_id is valid reverse-DNS before using it in find patterns. This stops glob injection.
- `find_app_files()` skips LaunchAgents named after common words like Music or Notes.
- Added comments explaining why `remove_file_list()` bypasses TOCTOU checks for symlinks.
- `brew_uninstall_cask()` treats exit code 124 as timeout failure, returns immediately.
2025-12-11 15:18:04 +08:00
2026-01-27 10:22:07 +08:00
Other changes:
2025-12-26 18:39:53 +08:00
2026-01-27 10:22:07 +08:00
- Symlink cleanup in `bin/clean.sh` goes through `safe_remove` now
- Orphaned helper cleanup in `lib/clean/apps.sh` switched to `safe_sudo_remove`
- ByHost pref cleanup checks bundle ID format first
2025-12-11 15:18:04 +08:00
2026-01-27 10:22:07 +08:00
## Path Validation
2025-12-11 15:18:04 +08:00
2026-01-27 10:22:07 +08:00
Every deletion goes through `lib/core/file_ops.sh` . The `validate_path_for_deletion()` function rejects empty paths, paths with `/../` in them, and anything containing control characters like newlines or null bytes.
2025-12-11 15:18:04 +08:00
2026-01-27 10:22:07 +08:00
**Blocked paths**, even with sudo:
2026-01-26 15:43:11 +08:00
2026-01-27 10:22:07 +08:00
```text
/ # root
/System # macOS system
/bin, /sbin, /usr # binaries
/etc, /var # config
/Library/Extensions # kexts
/private # system private
2025-12-28 21:30:39 +08:00
```
2026-01-27 10:22:07 +08:00
Some system caches are OK to delete:
2026-01-15 21:02:13 +08:00
2026-01-27 10:22:07 +08:00
- `/System/Library/Caches/com.apple.coresymbolicationd/data`
2026-01-15 21:02:13 +08:00
- `/private/tmp` , `/private/var/tmp` , `/private/var/log` , `/private/var/folders`
- `/private/var/db/diagnostics` , `/private/var/db/DiagnosticPipeline` , `/private/var/db/powerlog` , `/private/var/db/reportmemoryexception`
2025-12-28 21:30:39 +08:00
2026-01-27 10:22:07 +08:00
See `lib/core/file_ops.sh:60-78` .
2025-12-28 21:30:39 +08:00
2026-01-27 10:22:07 +08:00
When running with sudo, `safe_sudo_recursive_delete()` also checks for symlinks. Refuses to follow symlinks pointing to system files.
2025-12-28 21:30:39 +08:00
2026-01-27 10:22:07 +08:00
## Cleanup Rules
2025-12-28 21:30:39 +08:00
2026-01-27 10:22:07 +08:00
**Orphan detection** at `lib/clean/apps.sh:orphan_detection()` :
2025-12-28 21:30:39 +08:00
2026-01-27 10:22:07 +08:00
App data is only considered orphaned if the app itself is gone from all three locations: `/Applications` , `~/Applications` , `/System/Applications` . On top of that, the data must be untouched for at least 60 days. Adobe, Microsoft, and Google stuff is whitelisted regardless.
2025-12-28 21:30:39 +08:00
2026-01-27 10:22:07 +08:00
**Uninstall matching** at `lib/clean/apps.sh:uninstall_app()` :
2025-12-28 21:30:39 +08:00
2026-01-27 10:22:07 +08:00
App names need at least 3 characters. Otherwise "Go" would match "Google" and that's bad. Fuzzy matching is off. Receipt scans only look under `/Applications` and `/Library/Application Support` , not in shared places like `/Library/Frameworks` .
2025-12-28 21:30:39 +08:00
2026-01-27 10:22:07 +08:00
**Dev tools:**
2025-12-28 21:30:39 +08:00
2026-01-27 10:22:07 +08:00
Cache dirs like `~/.cargo/registry/cache` or `~/.gradle/caches` get cleaned. But `~/.cargo/bin` , `~/.mix/archives` , `~/.rustup` toolchains, `~/.stack/programs` stay untouched.
2026-01-11 09:26:04 +08:00
2026-01-27 10:22:07 +08:00
**LaunchAgent removal:**
2026-01-11 09:26:04 +08:00
2026-01-27 10:22:07 +08:00
Only removed when uninstalling the app that owns them. All `com.apple.*` items are skipped. Services get stopped via `launchctl` first. Generic names like Music, Notes, Photos are excluded from the search.
2026-01-11 09:26:04 +08:00
2026-01-27 10:22:07 +08:00
See `lib/core/app_protection.sh:find_app_files()` .
2025-12-28 21:30:39 +08:00
2026-01-27 10:22:07 +08:00
## Protected Categories
2025-12-28 21:30:39 +08:00
2026-01-27 10:22:07 +08:00
| Category | What's protected |
| -------- | ---------------- |
| System | Control Center, System Settings, TCC, `/Library/Updates` , Spotlight |
| VPN/Proxy | Shadowsocks, V2Ray, Tailscale, Clash |
| AI | Cursor, Claude, ChatGPT, Ollama, LM Studio |
| Time Machine | Checks if backup is running. If status unclear, skips cleanup. |
| Startup | `com.apple.*` LaunchAgents/Daemons always skipped |
2025-12-28 21:30:39 +08:00
2026-01-27 10:22:07 +08:00
See `lib/core/app_protection.sh:is_critical_system_component()` .
2025-12-28 21:30:39 +08:00
2026-01-27 10:22:07 +08:00
## Analyzer
2025-12-28 21:30:39 +08:00
2026-01-27 10:22:07 +08:00
`mo analyze` runs differently:
2025-12-29 19:06:04 +08:00
2026-01-27 10:22:07 +08:00
- Standard user permissions, no sudo
- Respects SIP
- Two keys to delete: press ⌫ first, then Enter. Hard to delete by accident.
- Files go to Trash via Finder API, not rm
2025-12-29 19:06:04 +08:00
2026-01-27 10:22:07 +08:00
Code at `cmd/analyze/*.go` .
2025-12-29 19:06:04 +08:00
2026-01-27 10:22:07 +08:00
## Timeouts
2025-12-29 19:06:04 +08:00
2026-01-27 10:22:07 +08:00
| Operation | Timeout | Why |
| --------- | ------- | --- |
| Network volume check | 5s | NFS/SMB/AFP can hang forever |
| App bundle search | 10s | mdfind sometimes stalls |
| SQLite vacuum | 20s | Skip if Mail/Safari/Messages is open |
| dyld cache rebuild | 180s | Skip if done in last 24h |
2025-12-28 21:30:39 +08:00
2026-01-27 10:22:07 +08:00
See `lib/core/base.sh:run_with_timeout()` .
2025-12-28 21:30:39 +08:00
2026-01-27 10:22:07 +08:00
## User Config
2025-12-28 21:30:39 +08:00
2026-01-27 10:22:07 +08:00
Put paths in `~/.config/mole/whitelist` , one per line:
2025-12-28 21:30:39 +08:00
```bash
2026-01-27 10:22:07 +08:00
# exact matches only
/Users/me/important-cache
~/Library/Application Support/MyApp
2025-12-28 21:30:39 +08:00
```
2026-01-27 10:22:07 +08:00
These paths are protected from all operations.
2025-12-28 21:30:39 +08:00
2026-01-27 10:22:07 +08:00
Run `mo clean --dry-run` or `mo optimize --dry-run` to preview what would happen without actually doing it.
2025-12-28 21:30:39 +08:00
2026-01-27 10:22:07 +08:00
## Testing
2025-12-28 21:30:39 +08:00
2026-01-27 10:22:07 +08:00
| Area | Coverage |
| ---- | -------- |
| File ops | 95% |
| Cleaning | 87% |
| Optimize | 82% |
| System | 90% |
| Security | 100% |
2025-12-28 21:30:39 +08:00
2026-01-27 10:22:07 +08:00
180+ test cases total, about 88% coverage.
2025-12-28 21:30:39 +08:00
```bash
2026-01-27 10:22:07 +08:00
bats tests/ # run all
bats tests/security.bats # security only
2025-12-28 21:30:39 +08:00
```
2026-01-27 10:22:07 +08:00
CI runs shellcheck and go vet on every push.
2025-12-28 21:30:39 +08:00
## Dependencies
2026-01-27 10:22:07 +08:00
System binaries used, all SIP protected:
2025-12-28 21:30:39 +08:00
2026-01-27 10:22:07 +08:00
| Binary | For |
| ------ | --- |
| `plutil` | plist validation |
| `tmutil` | Time Machine |
| `dscacheutil` | cache rebuild |
| `diskutil` | volume info |
2025-12-28 21:30:39 +08:00
2026-01-27 10:22:07 +08:00
Go libs in analyze-go:
2025-12-28 21:30:39 +08:00
2026-01-27 10:22:07 +08:00
| Lib | Version | License |
| --- | ------- | ------- |
| `bubbletea` | v0.23+ | MIT |
| `lipgloss` | v0.6+ | MIT |
| `gopsutil` | v3.22+ | BSD-3 |
| `xxhash` | v2.2+ | BSD-2 |
2025-12-28 21:30:39 +08:00
2026-01-27 10:22:07 +08:00
Versions are pinned. No CVEs. Binaries built via GitHub Actions.
2025-12-28 21:30:39 +08:00
2026-01-27 10:22:07 +08:00
## Limitations
2025-12-28 21:30:39 +08:00
2026-01-27 10:22:07 +08:00
| What | Impact | Workaround |
| ---- | ------ | ---------- |
| Needs sudo for system caches | Annoying first time | Docs explain why |
| 60-day wait for orphans | Some junk stays longer | Use `mo uninstall` manually |
| No undo | Gone is gone | Use dry-run first |
| English names only | Might miss localized apps | Falls back to bundle ID |
2025-12-28 21:30:39 +08:00
2026-01-27 10:22:07 +08:00
**Won't touch:**
2025-12-28 21:30:39 +08:00
2026-01-27 10:22:07 +08:00
- Your documents or media
- Password managers or keychains
- Files under `/etc`
- Browser history/cookies
- Git repos