syspolicyd: "Unable to parse ticket" / "error registering ticket: -1" on one Mac; stapled ticket identical to healthy Macs; system extension fails with -67050

We ship an Endpoint Security system extension inside a host app. On one managed Mac (macOS 26.6.2, build 25G83, arm64) the extension can't be activated, while the same package works on other Macs with the same macOS build.

WHAT WE SHIP AND HOW IT'S NOTARIZED

  • Host app: ElasticEndpoint.app (co.elastic.endpoint), Developer ID signed, notarized, with the ticket stapled (codesign -dvv shows "Notarization Ticket=stapled").
  • System extension: ElasticEndpoint.app/Contents/Library/SystemExtensions/co.elastic.systemextension.systemextension (co.elastic.systemextension), same Team ID, Developer ID signed. It was part of the same notarization submission as the host app but has no ticket stapled to itself (stapler validate says "does not have a ticket stapled to it").
  • Delivery: a root-owned service extracts the app into /Applications with tar (so no quarantine attribute) and then runs "ElasticEndpoint --install" as root to request activation.
  • Versions: first reported on 9.0.8, and the same on 9.5.1. 9.1.0 and 9.5.4 have the same layout.
  • Public packages: https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent-9.0.8-darwin-aarch64.tar.gz , with the app in data/elastic-agent-*/components/endpoint-security-resources.zip -> 64_Bit_Elastic_App_macOS.tgz. The 9.5.1 package is at the same URL pattern.

SYMPTOMS ON THE AFFECTED MAC

syspolicyd: [com.apple.syspolicy:default] Unable to parse ticket.
syspolicyd: [com.apple.syspolicy:default] error registering ticket: -1
sysextd: Error checking with notarization daemon: 3
sysextd: bundle code signature is not valid - does not satisfy requirement: -67050 code failed to satisfy specified code requirement(s)
sysextd: co.elastic.systemextension: extension failed to validate! uninstalling...
  • "spctl -a -vv -t execute" prints "accepted / source=Developer ID", not "Notarized Developer ID", for our app and for an unrelated vendor's notarized app. Healthy Macs print "Notarized Developer ID".
  • "syspolicy_check distribution" reports a notary error, and "codesign -R="notarized" --check-notarization" fails.

RULED OUT

  • The stapled ticket (Contents/CodeResources, 1716 bytes, SHA-256 e8679543f9934bd43b127210c10348f764b78a53360ec515ccbcb4afc0920e28) is byte-identical on the affected Mac, on a healthy Mac, and in the official 9.5.1 package.
  • The network: TLS to api.apple-cloudkit.com and valid.apple.com works, there's no proxy, and the clock is correct (sntp offset 0.03 s).

WHAT A HEALTHY MAC DOES (fresh macOS 26.6.2 VM, app without quarantine)

Running the app's binary produces: "Extracting ticket from bundle" -> "Registering stapled ticket with system" -> CloudKit fetch -> "Inserting ticket". /var/db/SystemPolicyConfiguration/Tickets gains rows in the "tickets" and "hashes" tables, including the extension's cdhash. sysextd then validates the extension locally ("isNotarized = 1"), so the extension's notarization is established through the host app's ticket.

If I truncate CodeResources on the VM, I get the same "Unable to parse ticket" / "-1" lines and then -67050. So on the affected Mac, ticket registration seems to fail even though the ticket file is intact.

A third-party write-up describes the same signature on one Mac ("stapler validate" exit 65 for every vendor's app): https://github.com/fsnow/cst/blob/main/docs/implementation/NOTARIZATION_TICKET_ISSUE.md They report that none of these helped: resetting the Tickets database with SIP off, restarting syspolicyd/trustd, a fresh user account, or OS upgrades up to macOS 27.0.1.

QUESTIONS

  1. What can make syspolicyd fail to parse or register a valid stapled ticket on a single Mac?
  2. Is there a supported way to repair ticket registration without erasing the Mac?
  3. Is it expected that sysextd validates nested code (the extension) only against the local ticket database, with no online fallback?
  4. What should we collect for you: a sysdiagnose, or a Feedback Assistant report? [FB number if filed]
Answered by DTS Engineer in 911101022

Glad to hear that you’re making progress.

Written by benchman_acc in 910871022
  1. Is it intended that syspolicyd refuses a ticket whose signing chain is trusted through a trust-settings override (Proceed) instead of the system anchor?

Yes [1].

In general, you shouldn’t be monkeying with trust settings for system certificates, and doing so can cause all sorts of weird problems.

Written by benchman_acc in 910871022
  1. Could anything other than admin or user trust settings make this chain evaluate to Proceed … ?

Not that I can think of. In my experience a .proceed trust result is always generated by trust settings.

Written by benchman_acc in 910871022
  1. If the behaviour is intended, "Unable to parse ticket" with a -1 error makes it hard to diagnose. Would a bug report asking for a clearer message be useful?

Yeah, you should definitely file a bug request better diagnostics here.

Please post your bug number, just for the record.

Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] I was gonna waffle about this but I had a look at the code and there’s an explicit check for .unspecified and a comment indicating that it requires the trust evaluation to be successful without user override.

So, that error means that Gatekeeper failed to parse, or failed to validate, your notarised ticket. That raises two possibilities

  • The ticket itself is corrupt.
  • Something is causing trust evaluation on the ticket’s certificate chain to fail.

I suspect it’s the latter, because the former would require the corruption to occur between the file on disk, which you know to be good, and the contents of that file in memory, and that sort of corruption is not exactly common.

I recommend that you do the following:

  1. Reproduce the problem, and specifically the steps that generate that Unable to parse ticket log entry.

  2. Capture the system log. The easiest option for this is:

    % sudo log collect --last 5m
    

    You could also trigger a sysdiagnose log. That’d make sense if you were filing a bug, and we may get to that, but for the moment a simple snapshot is gonna be easier.

  3. Dig into that log and locate the Unable to parse ticket log entry.

  4. Look backwards from that for log entries related to trust evaluation.

What do you see?

Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thanks Quinn, that pointed us in the right direction. On the affected Mac we captured a live log stream --level debug (plus log collect) while running spctl -a -vv -t execute on our app, and looked backwards from Unable to parse ticket as you suggested. We'd appreciate your confirmation of what we found.

AFFECTED MAC (macOS 26.6.2). Every ticket registration looks like this (multi-line trust details collapsed):

08:27:22.834198 syspolicyd: [com.apple.securityd:notarization] Registering stapled ticket with system
08:27:22.834318 syspolicyd: Created Activity ID: 0x1f2c261e, Description: SecTrustEvaluateIfNecessary
08:27:22.834656 trustd: [com.apple.securityd:serverxpc] XPC [syspolicyd[486]/1#41 LF=0] operation: trust_evaluate (8)
08:27:22.838963 trustd: [com.apple.securityd:trust] completed: <private> details: ({}, {}) result: 4
08:27:22.840541 trustd: [com.apple.securityd:trust] completed: <private> details: ({}, {}, {}) result: 1
08:27:22.840801 syspolicyd: [com.apple.syspolicy:default] Unable to parse ticket.
08:27:22.841143 syspolicyd: [com.apple.syspolicy:default] error registering ticket: -1
08:27:22.841174 syspolicyd: [com.apple.securityd:SecError] Error registering stapled ticket: Error Domain=NSOSStatusErrorDomain Code=-1 ...
08:27:22.841208 syspolicyd: [com.apple.securityd:notarization] checking with online notarization service for hash: ... 0x79126fe9ed660f77390d069a0dfae36188e9ba8f

The ticket then downloaded from CloudKit fails the same way (3-certificate evaluation with result 1, then "Unable to parse ticket"), and so does stapler validate for another vendor's stapled app.

HEALTHY MAC (clean macOS 26.6.2 VM, same app):

12:59:10.464799 syspolicyd: [com.apple.securityd:notarization] Registering stapled ticket with system
12:59:10.464837 syspolicyd: Created Activity ID: 0x277aa, Description: SecTrustEvaluateIfNecessary
12:59:10.465037 trustd: [com.apple.securityd:serverxpc] XPC [syspolicyd[207]/1#41 LF=0] operation: trust_evaluate (8)
12:59:10.466544 trustd: [com.apple.securityd:trust] completed: <private> details: () result: 4
12:59:10.467001 trustd: [com.apple.securityd:trust] completed: <private> details: () result: 4
12:59:10.467201 syspolicyd: Created Activity ID: 0x277ab, Description: SecKeyVerifySignature
12:59:10.471581 syspolicyd: [com.apple.syspolicy:default] Inserting ticket: <private>

The 3-certificate chain matches the one embedded in the ticket: Software Ticket Signing -> Apple System Integration CA 4 -> Apple Root CA - G3. Our reading is that result 1 is kSecTrustResultProceed (trusted because of an explicit trust setting) and result 4 is kSecTrustResultUnspecified (trusted through the built-in anchor).

REPRODUCTION. On the clean VM, we added an admin-domain override for Apple Root CA - G3:

sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain g3.pem

After that, "security dump-trust-settings -d" shows Apple Root CA - G3 with "Number of trust settings : 0". With the network up, we then got exactly the field symptoms:

  • the ticket chain evaluates to result 1, and "Unable to parse ticket" is logged for both the stapled and the downloaded ticket
  • spctl prints "source=Developer ID", and "stapler validate" exits with 65
  • our system extension fails with "Error checking with notarization daemon: 3" and -67050

"sudo security remove-trusted-cert -d g3.pem" fixed it immediately, without a reboot. We've asked the customer to check their trust settings, but haven't yet received the response for it.

QUESTIONS

  1. Is it intended that syspolicyd refuses a ticket whose signing chain is trusted through a trust-settings override (Proceed) instead of the system anchor?
  2. Could anything other than admin or user trust settings make this chain evaluate to Proceed, for example a configuration profile with a certificate payload? That would tell us what else to ask admins to look for.
  3. If the behaviour is intended, "Unable to parse ticket" with a -1 error makes it hard to diagnose. Would a bug report asking for a clearer message be useful? We're happy to file one with a sysdiagnose from the VM.

For reference, this third-party write-up describes the same symptom on one Mac, whose admin trust settings contained Apple Root CA - G3 and Developer ID Certification Authority: https://github.com/fsnow/cst/blob/main/docs/implementation/NOTARIZATION_TICKET_ISSUE.md

Accepted Answer

Glad to hear that you’re making progress.

Written by benchman_acc in 910871022
  1. Is it intended that syspolicyd refuses a ticket whose signing chain is trusted through a trust-settings override (Proceed) instead of the system anchor?

Yes [1].

In general, you shouldn’t be monkeying with trust settings for system certificates, and doing so can cause all sorts of weird problems.

Written by benchman_acc in 910871022
  1. Could anything other than admin or user trust settings make this chain evaluate to Proceed … ?

Not that I can think of. In my experience a .proceed trust result is always generated by trust settings.

Written by benchman_acc in 910871022
  1. If the behaviour is intended, "Unable to parse ticket" with a -1 error makes it hard to diagnose. Would a bug report asking for a clearer message be useful?

Yeah, you should definitely file a bug request better diagnostics here.

Please post your bug number, just for the record.

Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] I was gonna waffle about this but I had a look at the code and there’s an explicit check for .unspecified and a comment indicating that it requires the trust evaluation to be successful without user override.

Thanks Quinn, that's exactly what we needed. The footnote about the explicit check for .unspecified explains the behaviour, and it also tells us that an override in either the user or the admin domain triggers it, so we've asked the customer to check both.

I filed the Feedback: FB25283877. It asks for better diagnostics: a syspolicyd log line that names the certificate and the trust domain when a ticket's chain is trusted through an override (instead of "Unable to parse ticket" / -1), a matching hint in the output of stapler, spctl and syspolicy_check, and unredacted trust details in the trustd log lines. It includes a clean-VM reproduction with log excerpts from a failing and a healthy run.