[Bug] Native installer produces unsealed macOS app bundle rejected by code signature validation
Bug Description
Bug: native installer produces a malformed (unsealed) ClaudeCode.app → macOS reports it as "damaged and can't be opened"
Summary
The Claude Code native installer creates ~/.local/share/claude/ClaudeCode.app without the code-signing seal (Contents/_CodeSignature/CodeResources). The bundle's Mach-O binary carries an Anthropic Developer ID signature whose CodeDirectory indicates sealed resources must be present, but the bundle on disk has none. macOS therefore fails signature validation and shows:
"ClaudeCode.app" is damaged and can't be opened. You should move it to the Trash.
The bundle is not quarantined — this is not a Gatekeeper/quarantine prompt, it's a broken/incomplete signature. It is reproducible: claude install latest --force regenerates the same malformed bundle.
Environment
- Claude Code CLI: 2.1.190
- Affected app bundle:
~/.local/share/claude/ClaudeCode.app(CFBundleIdentifier = com.anthropic.claude-code,LSUIElement = true) - macOS: 26.5.1 (build 25F80), Apple Silicon (arm64)
- Installed native versions present: 2.1.183, 2.1.185, 2.1.186, 2.1.187, 2.1.190
- Launcher:
~/.local/bin/claude→ symlink →~/.local/share/claude/versions/2.1.190
Steps to reproduce
- Have the CLI manage the native build (auto-update or
claude install). - Trigger whatever launches the helper app (or simply double-click
~/.local/share/claude/ClaudeCode.app). - macOS shows the "damaged and can't be opened" dialog.
claude install latest --force→ reinstall succeeds, but the regenerated bundle is still malformed (same dialog).
Evidence
Malformed bundle layout (missing _CodeSignature/ and CodeResources):
ClaudeCode.app/Contents/
├── Info.plist
└── MacOS/claude # 217 MB Mach-O, signed Developer ID Application: Anthropic PBC (Q6L2SF6YDW)
A healthy reference bundle (the claude.app bundled inside Claude Desktop, v2.1.181) — for contrast, it has the seal:
claude.app/Contents/
├── _CodeSignature/ # present
├── CodeResources # present
├── Info.plist
└── MacOS/
Gatekeeper / codesign verdict on the malformed bundle:
$ spctl -a -vvv ClaudeCode.app
ClaudeCode.app: code has no resources but signature indicates they must be present
$ codesign --verify --deep --strict --verbose=2 ClaudeCode.app
ClaudeCode.app: code has no resources but signature indicates they must be present
No quarantine attribute (rules out a normal Gatekeeper download prompt):
$ xattr -l ClaudeCode.app
com.apple.macl: … # only this (TCC); no com.apple.quarantine
The embedded signature is genuine Anthropic, with hardened runtime + entitlements — the binary is fine; only the bundle seal is missing:
Identifier=com.anthropic.claude-code
Authority=Developer ID Application: Anthropic PBC (Q6L2SF6YDW)
TeamIdentifier=Q6L2SF6YDW
CodeDirectory … flags=0x10000(runtime)
Entitlements: com.apple.security.device.audio-input,
com.apple.security.automation.apple-events,
com.apple.security.cs.allow-jit,
com.apple.security.cs.allow-unsigned-executable-memory,
com.apple.security.cs.disable-library-validation
Likely root cause
When the installer materializes ClaudeCode.app, it writes Info.plist and the (separately signed) MacOS/claude binary but does not include/produce the bundle's _CodeSignature/CodeResources seal. Because the binary's CodeDirectory expects sealed resources, the bundle fails validation as a whole and macOS marks it "damaged." The shipped/notarized bundle should include the seal (as the Claude Desktop reference bundle does).
Impact
- The native helper app (voice dictation / URL opening / Apple Events) cannot be launched; users get a "damaged — move to Trash" dialog that wrongly implies malware/corruption.
- Confusing because the CLI itself (
~/.local/bin/claude) works perfectly — only the.appwrapper is broken. - Repeated trash-and-recreate by the updater left multiple stale
ClaudeCode.appcopies in~/.Trash.
Suggested fix
Have the installer either (a) ship/copy the complete signed .app bundle including Contents/_CodeSignature/CodeResources, or (b) re-sign the bundle after assembling it on disk so the seal matches the contents. A post-install codesign --verify --deep --strict check would catch this regression.
Local workaround (temporary; undone by next update)
Re-sign the assembled bundle locally, preserving entitlements and hardened-runtime flags:
codesign --force --deep --preserve-metadata=entitlements,flags -s - \
~/.local/share/claude/ClaudeCode.app
After this, codesign --verify --deep --strict reports "valid on disk / satisfies its Designated Requirement" and the app launches (it is not quarantined). Note this…
Note: Content was truncated.
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗