Why Gatekeeper says your app is damaged, and how to fix it

Updated · Dmytro Virych

Guide · 3 min read

Gatekeeper's "damaged and can't be opened" message almost always means a broken or incomplete code signature, not a corrupted download — running codesign -vvv --deep --strict and spctl -vvv --assess --type exec on the app shows exactly which check failed.

Your app opened fine on your own Mac. Then a buyer downloads it, double-clicks it, and macOS refuses outright — the dialog says the app is damaged and belongs in the Trash. That is not Apple reporting malware. It is Gatekeeper reporting that a code-signature check failed, and the fix is almost never re-downloading the app. It is finding which check failed and re-signing correctly.

Apple documents the checks its own notary service runs, in order, in Resolving common notarization issues. Run the build through the same checks yourself with codesign and spctl before you ship the next one.

Is the signature actually valid?

Start here. If you modified the app bundle after signing it — repacked it into a different disk-image tool, dropped an update in place, edited Info.plist — the signature no longer matches the bundle. Apple's troubleshooting page is direct about the result: without a valid signature, "notarization fails with the following message: The signature of the binary is invalid."

Check it the same way the notary service does:

codesign -vvv --deep --strict /path/to/YourApp.app

Apple's own description of the three flags: vvv performs "a verification with elevated verbosity," deep ensures "the utility checks nested code content," and strict "increases the restrictiveness of the validation to match that required by notarization." A clean signature reports no problems; a broken one names the exact nested binary — a helper tool, a framework, an XPC service — that no longer matches what was signed.

Did you sign with the right kind of certificate?

A Mac App Distribution certificate, or a self-signed one, produces something that looks signed but that Gatekeeper will not accept for software distributed outside the App Store: "The binary is not signed with a valid Developer ID certificate." Sign apps, command-line tools and disk images with a Developer ID Application certificate; sign installer packages separately with a Developer ID Installer certificate.

Does the signature actually carry a secure timestamp?

Xcode only adds a secure timestamp during its archive and export workflows. A custom export step — a hand-rolled build script, a CI pipeline that calls codesign directly — can skip it, and Apple's notary service then reports "The signature does not include a secure timestamp." Check for one directly:

codesign -dvv /path/to/YourApp.app

Apple's read on the output: a signature with a secure timestamp shows a Timestamp line with a date, while "the presence of Signed Time in the output indicates the binary doesn't have a secure timestamp" instead. Getting a timestamp means the signing machine has to reach timestamp.apple.com at the moment it signs — a CI runner with restricted outbound access at that step produces exactly this failure, and nothing else in the build looks wrong.

Is the hardened runtime actually turned on?

Signing through Xcode's standard export enables it by default. A custom codesign invocation that leaves it off gets "The executable does not have the hardened runtime enabled." Add it explicitly if you sign outside Xcode:

codesign --options=runtime --timestamp \
  -s "Developer ID Application: Your Name (TEAMID)" \
  /path/to/YourApp.app

Will Gatekeeper actually let it run?

codesign only confirms the signature is well-formed. spctl answers the question that actually matters to a customer: what will Gatekeeper decide on their Mac, right now. Apple describes it as checking "if the software to be notarized will run with the system policies currently in effect":

spctl -vvv --assess --type exec /path/to/YourApp.app

Add --raw for the full verdict as a property list, including which requirement failed.

The order to check things in

Work top to bottom — a broken signature hides everything downstream, since spctl cannot assess code it cannot first verify:

  1. codesign -vvv --deep --strict — is the signature valid at all?
  2. Was it signed with a Developer ID Application or Installer certificate, not a Mac App Distribution or self-signed one?
  3. codesign -dvv — does the output show a Timestamp, not just a Signed Time?
  4. Is the hardened runtime enabled (--options=runtime)?
  5. spctl -vvv --assess --type exec — does Gatekeeper's own policy engine agree the app is fine?

Fix the first failure, re-sign, and re-run the same command before moving to the next one. Each of these is a real message from the notary service, not a guess — a build that clears all five is a build Gatekeeper has no signature problem left to call damaged over.

#codesign#notarization

Sources