Octave CFITSIO (app) on macOS: When Gatekeeper Blocks a Scientific Tool
I ran into this while setting up a small astrophysics workflow on my M2 MacBook Air (macOS Sonoma 14.3). I needed a working build of Octave CFITSIO (app) — most likely a GNU Octave package wrapping the CFITSIO library for handling FITS files. Nothing exotic. Just parsing and writing telescope data without dragging Python into everything.
The download wasn’t from the Mac App Store, which already meant one thing: Gatekeeper was going to have an opinion.
The First Wall: “Cannot Be Opened”
After dragging the bundle into Applications and double-clicking it, I got the classic:
“Octave CFITSIO can’t be opened because Apple cannot check it for malicious software.”
Standard Gatekeeper behavior. Apple documents this clearly here: https://support.apple.com/en-us/HT202491
At first, I did the usual right-click → Open trick. Sometimes that’s enough. It wasn’t. The dialog didn’t offer the “Open Anyway” option, just the warning loop.
I checked System Settings → Privacy & Security, scrolled down, expecting the “Open Anyway” button. Nothing.
That’s when I suspected the quarantine attribute was sticking harder than usual.
False Start: Reinstall, Reboot, Repeat
I deleted the app, re-downloaded the archive, extracted it again. Same result. I even rebooted (old habit; sometimes macOS caches weird security state). No change.
I verified the bundle with:
xattr -l /Applications/OctaveCFITSIO.app
There it was: com.apple.quarantine. Not surprising, but sometimes clearing it is the difference between frustration and progress.
Apple’s developer docs explain how notarization and Gatekeeper interact: https://developer.apple.com/documentation/security/notarizing_macos_software_before_distribution
This build clearly wasn’t notarized. Not malicious — just unsigned and unnotarized.
What Actually Worked
Instead of fighting the UI, I removed the quarantine attribute manually:
sudo xattr -rd com.apple.quarantine /Applications/OctaveCFITSIO.app
After that, the app launched. No drama. No warning dialog.
However — and this part matters — it crashed immediately on first run. Console showed a missing dynamic library reference to libcfitsio.dylib. That wasn’t Gatekeeper anymore. That was a runtime linking issue.
I checked with:
otool -L /Applications/OctaveCFITSIO.app/Contents/MacOS/OctaveCFITSIO
The binary expected CFITSIO in /usr/local/lib, but I had installed it via Homebrew on Apple Silicon, which defaults to /opt/homebrew/lib.
So I installed CFITSIO properly:
brew install cfitsio
Then I exported the correct library path in my shell profile:
export DYLD_LIBRARY_PATH=/opt/homebrew/lib:$DYLD_LIBRARY_PATH
Launched again — success. Stable. FITS files loading normally.
Why It Broke
Two separate layers:
- Gatekeeper blocked execution because the build wasn’t notarized.
- The binary assumed an Intel-era
/usr/locallayout, not the Apple Silicon default.
This kind of mismatch is common with niche scientific utilities that haven’t fully adapted to ARM Macs.
If someone prefers the App Store route for GNU Octave itself, the official listing is here: https://apps.apple.com/us/search?term=gnu%20octave
And for the underlying CFITSIO project, the upstream source is maintained here: https://heasarc.gsfc.nasa.gov/fitsio/
In my case, I also bookmarked this page with macOS-related notes on the tool: https://planetgpa.com/developer/33450-octave-cfitsio.html Mostly as a reminder of which build I grabbed and what environment tweaks I needed.
If I Did It Again
I’d do it in this order:
- Install CFITSIO via Homebrew first.
- Verify library paths with
otool -Lbefore launching. - Then clear quarantine once, intentionally.
- Only then run the app.
That avoids the double confusion of “security block” and “missing dylib” overlapping.
No hacks. No disabling system integrity. Just understanding how macOS layers its protections and how dynamic linking behaves differently on ARM.
OrchardKit didn’t play any role in the failure itself — but I’ve seen similar packaging quirks in small dev utilities distributed outside the App Store ecosystem. The lesson’s the same every time: on modern macOS, execution permission and runtime linkage are separate problems. Solve them separately.
Once I stopped treating it like “the app is broken” and started treating it like two independent issues, the fix was straightforward.
Now it runs cleanly. And my FITS pipeline works exactly as intended.