Skip to content

fix(clean): never delete endpoint-security agent caches - #1154

Merged
tw93 merged 2 commits into
tw93:mainfrom
ImL1s:fix/edr-cache-tamper-protection
Jun 25, 2026
Merged

fix(clean): never delete endpoint-security agent caches#1154
tw93 merged 2 commits into
tw93:mainfrom
ImL1s:fix/edr-cache-tamper-protection

Conversation

@ImL1s

@ImL1s ImL1s commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Summary

mo clean and mo analyze deleted rebuildable GPU/Metal shader caches, code-signature clones, and old user-owned files under every app's per-user Darwin folder (/private/var/folders/.../C, .../X, .../T). On a Mac managed with CrowdStrike Falcon this removed files inside the Falcon sensor's own cache container (com.crowdstrike.falcon.App/com.apple.metalfe), which tripped the sensor's tamper protection (IOA MacFalconSensorTamper, MITRE T1562.001) and was flagged as malware by the company's security team.

The fix follows the repo's data/logic split and protects every deletion path:

  • app_protection_data.sh: new ENDPOINT_SECURITY_BUNDLE_PREFIXES array of endpoint-security / EDR / MDM vendor bundle ids (CrowdStrike, SentinelOne, ESET, Jamf, GlobalProtect, Cisco Secure Client), mirroring the vendors already in OFFICIAL_UNINSTALLER_RULES.
  • app_protection.sh: is_endpoint_security_cache_path() iterates the array and matches a vendor id under /private/var/folders (or the /var/folders symlink form).
  • file_ops.sh: validate_path_for_deletion() rejects these paths before its /private/var/folders allowlist — so every safe_remove / safe_sudo_remove caller is covered, not only the cleanup sweeps.
  • lib/clean/system.sh (GPU-cache + code_sign_clone sweeps), lib/clean/user.sh (_clean_darwin_user_runtime_dir), and should_protect_path() also pre-check the predicate.
  • cmd/analyze/delete.go: mo analyze refuses to move these paths to Trash (validateTrashTarget / isProtectedAnalyzeDeletePath), mirroring the shell predicate.

The match is protection-only: rebuildable caches for all other apps are still reclaimed.

Safety Review

  • Affects clean (system + user cleanup) and analyze (interactive Trash) deletion behavior.
  • Affects protected-directory policy: it adds protection (skips deletions) for EDR/MDM agent paths under var/folders, enforced centrally in validate_path_for_deletion() so no future caller can regress. It does not broaden any deletion matcher, remove an existing protection, or change sudo / Trash / dry-run / operation-logging behavior.
  • The predicate is anchored to /private/var/folders/* and /var/folders/* (an unrelated .../var/folders/... path cannot match) and is protection-only: the worst case is leaving a few MB of a security agent's rebuildable cache unreclaimed; it can never cause an unwanted deletion. Non-security products (e.g. com.cisco.webex) are not matched.

Tests

  • ./scripts/check.sh (shfmt, shellcheck, go vet, syntax) and MOLE_TEST_NO_AUTH=1 ./scripts/test.sh (full bats + Go): pass.
  • core_safe_functions.bats: predicate matches every vendor across C/ / X/ / T/, rejects normal apps / com.cisco.webex / non-Darwin .../var/folders/... / non-var/folders paths; validate_path_for_deletion rejects the Falcon path but allows a normal Darwin cache shard.
  • clean_system_maintenance.bats: GPU-cache and code_sign_clone sweeps skip EDR paths while reclaiming a normal app's cache.
  • clean_user_core.bats: _clean_darwin_user_runtime_dir skips an EDR agent's user-owned cache while reclaiming a normal old cache file.
  • cmd/analyze/delete_test.go: validateTrashTarget rejects EDR Darwin caches and allows a normal Darwin cache.

Safety-related changes

  • Adds ENDPOINT_SECURITY_BUNDLE_PREFIXES (data) + is_endpoint_security_cache_path() (shell) + a Go mirror, enforced at validate_path_for_deletion() (covers all shell deletion callers), the three clean sweeps, should_protect_path(), and mo analyze's Trash validation. Protection-only: no new deletion surface, no change to sudo / Trash / dry-run / logging.

@ImL1s
ImL1s requested a review from tw93 as a code owner June 24, 2026 11:10
@ImL1s
ImL1s force-pushed the fix/edr-cache-tamper-protection branch 2 times, most recently from b7b0136 to e88ff0b Compare June 24, 2026 11:56
@ImL1s ImL1s changed the title fix(clean): skip endpoint-security agent caches during system cleanup fix(clean): skip endpoint-security agent caches during cleanup Jun 24, 2026
@ImL1s
ImL1s force-pushed the fix/edr-cache-tamper-protection branch from e88ff0b to e3f7c07 Compare June 24, 2026 12:29
@ImL1s ImL1s changed the title fix(clean): skip endpoint-security agent caches during cleanup fix(clean): never delete endpoint-security agent caches Jun 24, 2026
mo clean and mo analyze deleted rebuildable Metal/GPU shader caches,
code-signature clones, and old user-owned files under each app's per-user
Darwin folder (/private/var/folders/.../{C,X,T}). For CrowdStrike Falcon this
removed files inside the sensor's own container, tripping its tamper protection
(IOA MacFalconSensorTamper, MITRE T1562.001), which corporate security reports
as malware.

Add ENDPOINT_SECURITY_BUNDLE_PREFIXES (app_protection_data.sh) listing EDR/MDM
vendor bundle ids (CrowdStrike, SentinelOne, ESET, Jamf, GlobalProtect, Cisco
Secure Client; mirrors OFFICIAL_UNINSTALLER_RULES) and the predicate
is_endpoint_security_cache_path() matching them under /private/var/folders (or
the /var/folders symlink form). Enforce it at every deletion path:

- validate_path_for_deletion() rejects these paths before the var/folders
  allowlist, so all safe_remove / safe_sudo_remove callers are covered, not
  just the cleanup sweeps.
- The clean sweeps (GPU cache, code_sign_clone, Darwin user runtime) and
  should_protect_path() also pre-check it.
- mo analyze (Go) refuses to move them to Trash via validateTrashTarget().

Protection-only: rebuildable caches for every other app are still reclaimed.

Tests: predicate + validate_path_for_deletion coverage in
core_safe_functions.bats, skip-EDR regressions for the system sweeps
(clean_system_maintenance.bats) and user runtime cleanup (clean_user_core.bats),
and analyze Trash protection (cmd/analyze/delete_test.go).
@ImL1s
ImL1s force-pushed the fix/edr-cache-tamper-protection branch from e3f7c07 to f042601 Compare June 24, 2026 13:06
@tw93
tw93 merged commit 1eb04fe into tw93:main Jun 25, 2026
@tw93

tw93 commented Jun 25, 2026

Copy link
Copy Markdown
Owner

@ImL1s thank you for the detailed fix and context. I added one test update before merging:

  • tightened the safe_sudo_remove protected-path return-code test to use the real CrowdStrike var/folders cache shape
  • added a Go test to keep mo analyze's endpoint-security prefix list in sync with ENDPOINT_SECURITY_BUNDLE_PREFIXES from the shell data

Merged to main in 1eb04fe. This will be included in the next release; users can try the main build via mo update --nightly after Nightly refreshes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants