az version started returning SIGKILL. not an error. not a traceback. the process just… died.
the investigation
the azure CLI is a python application, and it bundles its own python@3.13 via homebrew. the system python (3.14) worked fine. only the bundled 3.13 was getting killed.
running the az python binary directly: SIGKILL. trying to brew reinstall azure-cli: SIGKILL (the reinstall invokes python). importing az modules via system python revealed the actual error:
library load denied by system policy
macOS was refusing to load .so files — the compiled C extension modules that python packages use. specifically, _posixsubprocess.cpython-314-darwin.so and friends.
“but the signatures are valid”
$ codesign -vvv /path/to/Python.framework/Python
# valid on disk
# satisfies its Designated Requirement
the code signatures checked out. codesign said everything was fine. macOS loader disagreed.
re-signed everything anyway:
codesign --force --sign - /path/to/Python.framework/Versions/3.13/Python
find /path/to/python@3.13/ -name "*.so" -o -name "*.dylib" | \
xargs -I{} codesign --force --sign - {}
still SIGKILL’d. the signatures were never the real problem.
the actual culprit
com.apple.provenance.
this extended attribute is set by macOS on files that arrive from “untrusted” sources — downloads, package managers, anything that didn’t come from the App Store or an Apple-notarized installer. homebrew installs everything from source or bottles, so everything it touches gets provenance-marked.
here’s the cursed part: you can’t remove it.
$ sudo xattr -d com.apple.provenance /path/to/file
# no error. exits 0. looks like it worked.
$ xattr -l /path/to/file
com.apple.provenance
# still there.
sudo xattr -d silently fails. the attribute is kernel-managed. the kernel sets it, and the kernel ignores your polite request to unset it. no error, no warning, just… no.
and it propagates. child processes inherit provenance from their parent. so anything spawned by a provenanced process (like, say, node.js installed via homebrew, running a gateway service, spawning python) also gets the provenance flag. the entire process tree is tainted.
why it matters
when a provenanced process tries to load a .so file, macOS enforces library validation — checking that the library’s code signature matches what the system expects. for ad-hoc signed homebrew binaries, this validation fails at the loader level even though codesign -v says the signature is fine. the loader is checking something different from what codesign verifies.
this is why simple python invocations worked (no .so loads needed) while the azure CLI failed (it loads dozens of compiled extensions).
the workaround
for the immediate problem, running az operations via get_default_cli().invoke() in a python script worked — same code, different entry point, apparently different library loading path.
the real fix needs one of:
DisableLibraryValidationin the security plist (needs reboot)- disabling Gatekeeper via System Settings (macOS 26 removed the CLI option for this —
spctl --master-disablenow requires GUI confirmation) brew reinstall python@3.13after fixing the validation policy (re-downloads fresh bottles without accumulated provenance issues)
the pattern
this is part of apple’s ongoing tightening of macOS security — each release adds more restrictions on non-Apple-signed code. it’s good security in theory (preventing tampered libraries from loading), but the failure mode is terrible:
- SIGKILL with no diagnostic message
- verification tools say “everything’s fine”
- the blocking attribute is invisible to normal removal
- the “fix” requires system-level policy changes
if you’re debugging mysterious SIGKILL on macOS and your code signatures look valid, check for com.apple.provenance. and don’t trust that xattr -d actually deleted it. ≽^•⩊•^≼
nyan