Skip to content

Add v3: Apple Silicon / SSV-aware bypass (fixes macOS 26 re-enrollment + FileVault Recovery) - #170

Open
marclllaks wants to merge 1 commit into
assafdori:mainfrom
marclllaks:macos26-ssv-bypass-v3
Open

Add v3: Apple Silicon / SSV-aware bypass (fixes macOS 26 re-enrollment + FileVault Recovery)#170
marclllaks wants to merge 1 commit into
assafdori:mainfrom
marclllaks:macos26-ssv-bypass-v3

Conversation

@marclllaks

Copy link
Copy Markdown

What this adds

A new bypass-mdm-v3.sh that fixes why the bypass stops working on Apple Silicon + recent macOS (verified against macOS 26.5.1 / build 25F80, Apple Silicon).

Root cause it fixes

v1/v2 write the /etc/hosts block and the ConfigurationProfiles markers to the System volume (/Volumes/<SystemVol>/…). On Apple Silicon the OS boots from a sealed, read-only snapshot of the System volume; the live, mutable /etc/hosts and /var/db/ConfigurationProfiles physically live on the Data volume (via /etc → /private/etc, /var → /private/var, and the /private firmlink). So those writes never reach the volume the running OS reads — which is why the block "disappears" after an update and the enrollment nag returns. v3 targets the Data volume for everything.

Other fixes

  • FileVault / Recovery: locate the Data volume by APFS role (not name) and diskutil apfs unlockVolume it. Fixes the "Could not detect data volume" failure on modern Macs where FileVault is on by default (Critical: Script fails with FileVault encrypted volumes and unmounted Data volume #143).
  • macOS 26 daemon: cloudconfigurationd no longer exists on Tahoe; the work moved to com.apple.ManagedClient.enroll. v3 targets the current daemon and disables it via a launchd override on the Data volume, so it survives the System-volume reseal a macOS update performs (addresses the "popup returns after updating to 26.5" reports, e.g. Does this work on the new MacOS 26.5 #164).
  • Domain list: blocks iprofiles.apple.com (the device-side activation fetch — the load-bearing one) plus the org's own MDM host read from the activation record. Deliberately leaves gdmf.apple.com and albert.apple.com unblocked so Software Update and iMessage/FaceTime keep working.
  • Two modes:
    • Suppress enrollment only — for an already-set-up Mac that just nags; no user created, data untouched.
    • Full bypass — creates a temp admin + .AppleSetupDone, then suppresses (the original use case).

Notes

  • Existing bypass-mdm.sh / bypass-mdm-v2.sh are left unchanged.
  • Documents the hard limit clearly: this is local suppression, not de-enrollment; the serial stays in the org's ABM, so it can reappear after major updates (re-run) and the permanent fix is the org releasing the serial.

🤖 Generated with Claude Code

v1/v2 write the hosts block and ConfigurationProfiles markers to the System
volume, but on Apple Silicon the OS boots from a sealed read-only snapshot —
the live /etc/hosts and /var/db/ConfigurationProfiles physically live on the
Data volume (via /etc->/private/etc, /var->/private/var and the /private
firmlink). Those edits never reach the running OS and "disappear" after an
update. v3 targets the Data volume for everything.

Also:
- Locate + unlock the FileVault-encrypted Data volume in Recovery, by APFS
  role rather than name (fixes "Could not detect data volume" on modern Macs).
- Target the current enrollment daemon (com.apple.ManagedClient.enroll);
  cloudconfigurationd no longer exists on macOS 26 Tahoe.
- Disable the enroll daemon via a launchd override on the Data volume so it
  survives the System-volume reseal an update performs.
- Block iprofiles.apple.com (the device-side fetch) plus the org's own MDM
  host read from the activation record; deliberately leave gdmf/albert alone
  so Software Update and iMessage/FaceTime keep working.
- Two modes: "suppress enrollment only" (already-set-up Mac) and "full bypass".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@tomtomtestg1

Copy link
Copy Markdown

Hi, has anyone tested this? Can I run it on 26.3.1 and upgrade afterwards, or should I upgrade first and then run this in recovery mode?

@mateussiqueira

Copy link
Copy Markdown

Revisão técnica do PR #170 — v3

Parabéns pelo trabalho, @marclllaks. A análise da causa raiz (System Volume selado em Apple Silicon) está correta, e a solução de escrever no Data Volume via /private é a abordagem certa.

Pontos fortes

  • ✅ Detecção do Data Volume por APFS role (robusto, independente de nome)
  • ✅ Suporte a FileVault com diskutil apfs unlockVolume
  • ✅ Bloqueio de iprofiles.apple.com (o endpoint crítico) + servidor MDM da org
  • ✅ launchd override no Data Volume (sobrevive a reseal do System Volume)
  • ✅ Dois modos (suppress-only + full bypass)
  • gdmf.apple.com e albert.apple.com não bloqueados (importante)

Sugestões de melhoria

  1. set -euo pipefail sugerido no topo para safety (shellcheck recomenda). Hoje o script usa set -o pipefail apenas.

  2. resolve_data_volume() poderia ser mais resiliente:

    • O awk atual depende de diskutil apfs list encontrar o pattern (Data) em uma linha que também contenha diskNsM. Em alguns layouts o token pode vir em posição diferente.
    • Sugestão: usar diskutil apfs list -plist + /usr/libexec/PlistBuddy para extrair por tipo de volume de forma deterministico (similar ao que vc já faz com launchd).
  3. Path do launchd override: $data_mount/private/var/db/com.apple.xpc.launchd/disabled.plist — esse caminho funciona no macOS 26? A localização do disabled.plist mudou entre versões do macOS. Vale documentar quais versões foram testadas.

  4. Marcador .cloudConfigProfileInstalled no Data Volume: a config profile check do macOS olha no Data Volume (/private/var/db/ConfigurationProfiles), mas seria bom confirmar se o marker cloudConfigProfileInstalled é de fato lido dali ou se o macOS também checa no System Volume.

  5. Erro de digitação na descrição do PR: "repreated" → "repeated" (linha 13 do PR body). Detalhe menor.

Conflito com #144

O PR #144 (nostitos) modifica bypass-mdm-v2.sh com correções de FileVault/detecção de volumes que são parcialmente resolvidas pelo seu v3. Sugiro coordenar com o autor para rebaser o #144 em cima do seu v3, já que v3 resolve os mesmos problemas de forma mais ampla.

Veredito

PR de alta qualidade, bem documentado, mergeável (sem conflitos). Aceitar após considerar as sugestões acima.

@mateussiqueira

Copy link
Copy Markdown

Hey @marclllaks, nice work on v3. You nailed the root cause — v1/v2 writing to the System volume is the whole reason the bypass stops working after updates on Apple Silicon. Writing to the Data volume via /private is the right fix.

A few things I noticed while going through the code:

1. set -euo pipefail — you have set -o pipefail but adding -euo would catch more issues early. Without -e, the script keeps going even if diskutil mount or rm fails. Small change, big safety net.

2. The awk in resolve_data_volume() — it looks for (Data) in a line and then scans each field for a diskNsM pattern. The problem is that diskutil apfs list uses tree-drawing characters (│, ├, └) that shift the column positions, so the right token might not be where awk thinks it is. A more robust approach would be:

diskutil apfs list 2>/dev/null | awk '/\\(Data\\)/ && match($0, /disk[0-9]+s[0-9]+/) {print substr($0, RSTART, RLENGTH); exit}'

This uses regex match on the whole line instead of splitting by whitespace. Handles the tree characters cleanly.

3. The launchd override path$data_mount/private/var/db/com.apple.xpc.launchd/disabled.plist — Im not sure this path is the same on macOS 26 vs 15 vs 14. Apple moved it around a few times. Would be good to test or at least document which macOS versions were validated.

4. gdmf.apple.com and albert.apple.com — good call leaving those unblocked so Software Update and iMessage keep working. Did you consider also leaving ppq.apple.com unblocked (its needed for some App Store functionality)?

5. Minor typo in the PR description: "repreated" should be "repeated".

On #144 — nostitos PR fixes FileVault/mount issues in v2, but your v3 already handles most of those cases. Might be worth coordinating with them to rebase their work on top of v3 rather than having two competing solutions.

Overall the PR is solid and well-documented. Would love to see it merged after the awk fix. Let me know if you want me to submit a PR with these tweaks to your branch.

@marclllaks

Copy link
Copy Markdown
Author

Hi, has anyone tested this? Can I run it on 26.3.1 and upgrade afterwards, or should I upgrade first and then run this in recovery mode?

Hi @tomtomtestg1 this is how I did it and it worked for me:

  • I bypassed the mdm with the normal V2 script
  • I upgraded the mac, and used it a bit, then I got a notification that I should enroll in MDM, I clicked later
  • I turned off the Mac, entered recovery mode, and ran my V3 script, and choose "Suppress enrollment only", this way you don't have to reset the Mac.

It has been working so far for me, no enrollment notification, no device management detected in the settings.

@assafdori

Copy link
Copy Markdown
Owner

Definitely looks interesting I'll give it a shot myself, do you care updating relevant readme sections to support this possible merge?

@mateussiqueira

Copy link
Copy Markdown

This is a critical distinction. On Apple Silicon, the system volume is a cryptographically sealed SSV (Signed System Volume). Any writes to /System/ are silently dropped or cause snapshot breakage. The correct approach is to target only the Data volume (mounted at /Volumes/Macintosh HD - Data in Recovery).

Key differences for AS Macs:

  • DEP markers live on the Data volume under /private/var/db/ConfigurationProfiles/Settings/
  • The hosts file is at /private/etc/hosts on the Data volume
  • Launchd overrides are at /private/var/db/com.apple.xpc.launchd/disabled.plist on the Data volume
  • Additional daemons like com.apple.activationd and com.apple.ManagedClient.cloudConfiguration need to be disabled

If you're writing a PR for this, also include user-level cleanup (~/Library/Preferences/com.apple.mdm.*) which is the missing piece that causes re-enrollment after login. For reference, unleash (github.com/mateussiqueira/unleash) was built SSV-aware from day 1 and handles all of these.

aquilu added a commit to aquilu/bypass-mdm that referenced this pull request Jul 26, 2026
Robustez v2: SSV/hosts + FileVault + daemon disable + dominios (de assafdori#170)
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.

4 participants