Sparkle's AppInstaller post-stage-1 XPC listener accepts unvalidated connections, allowing spoofed appcast item data injection
Description
Summary
AppInstaller post-stage-1 XPC listener accepts unvalidated connections, allowing spoofed appcast item data injection.
Details
Autoupdate/AppInstaller.m's shouldAcceptNewConnection: only enforces SUCodeSigningVerifier validateConnection: before stage 1 completes. After _performedStage1Installation = YES, new connections to the registered Mach service -spki are accepted from any local process without team-ID or code-signing checks.
The following chain of events enables an attacker to inject a spoofed SPUSentUpdateAppcastItemData payload:
- Installer finishes unarchiving the update successfully (
_willCompleteInstallationis set). - The app responsible for updating the bundle crashes or is forcefully quit before it has a chance to send
SPUSentUpdateAppcastItemDatato the installer. There is no user interaction between the prior step and this one, so the timing window is tight. - After stage 1 of the installer is performed (
_performedStage1Installation = YES), but before final installation completes (since all services are cleaned up by then), an attacker process connects to the-spkiMach service - no code-signing validation is enforced - and sends a spoofedSPUSentUpdateAppcastItemDatamessage containing an attacker-craftedSUAppcastItem. - A Sparkle-aware app that checks for updates on the bundle being updated launches before installation completes. The progress agent re-broadcasts the spoofed
SUAppcastItemon its-spksstatus service, and the launching app displays attacker-controlled release notes (name, version, critical flag).
Note: Sparkle can be used to update other app bundles, so the "app doing the updating" and the "app being updated" are not necessarily the same bundle.
In the system-domain case (SPUUsesSystemDomainForBundlePath = true), the AppInstaller runs as root via SMJobSubmit to kSMDomainSystemLaunchd, and the Mach service is reachable by any local user process.
Affected versions: 2.x branch including 2.9.1.
Impact
A local user-level process can inject a forged SUAppcastItem (arbitrary name, version, critical flag) into the progress agent's status broadcast. Other Sparkle-aware clients on the system will display attacker-controlled release notes as authoritative installation state.
The integrity of the installed code is not affected - the bundle moved into place is the legitimate, signature-validated update from stage 1. The impact is limited to UI spoofing of installation metadata.
Remediation
Enforce SUCodeSigningVerifier validateConnection: on all new connections regardless of installation stage, or disallow SPUSentUpdateAppcastItemData after the active connection invalidates.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
AppInstaller XPC listener in Sparkle 2.x accepts unvalidated connections after stage 1, allowing local attackers to spoof appcast item data.
Vulnerability
The AppInstaller XPC listener in Autoupdate/AppInstaller.m only enforces SUCodeSigningVerifier validateConnection: before stage 1 completes. After _performedStage1Installation = YES, new connections to the registered Mach service -spki are accepted from any local process without team-ID or code-signing checks. This affects all versions in the 2.x branch including 2.9.1 [1][2].
Exploitation
A local attacker can exploit the vulnerability by timing a connection after the installer finishes unarchiving the update and the updating app crashes or is forcefully quit before sending SPUSentUpdateAppcastItemData. The attacker then connects to the -spki service and sends a spoofed SPUSentUpdateAppcastItemData message containing a crafted SUAppcastItem. If a Sparkle-aware app launches before installation completes, the progress agent re-broadcasts the spoofed item on its -spks service, displaying attacker-controlled release notes (name, version, critical flag). In the system-domain case (SPUUsesSystemDomainForBundlePath = true), the service runs as root and is reachable by any local user [1][2].
Impact
Successful injection allows an attacker to forge the update information displayed to the user, misleading them with false release notes, version numbers, or critical status. This undermines the trust in the update mechanism but does not directly lead to code execution or privilege escalation beyond the local process context [1][2].
Mitigation
No fixed version has been disclosed in the available references. Users should monitor the Sparkle project for a patch. Restricting local access to the affected Mach services may reduce the attack surface, but no official workaround is provided [1][2].
AI Insight generated on May 29, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
3<= 2.9.1+ 1 more
- (no CPE)range: <= 2.9.1
- (no CPE)range: >=2.0, <=2.9.1
Patches
36e370a5ab829Enforce connection to installer to be validated before receiving appcast item data (#2876)
1 file changed · +7 −2
Autoupdate/AppInstaller.m+7 −2 modified@@ -97,6 +97,7 @@ @implementation AppInstaller // Setting _performedStage1Installation on main thread must be synchronzied with reading it from new connection handler BOOL _performedStage1Installation; + BOOL _receivedAppcastItemData; BOOL _performedStage2Installation; BOOL _performedStage3Installation; @@ -142,9 +143,9 @@ - (BOOL)listener:(NSXPCListener *)__unused listener shouldAcceptNewConnection:(N BOOL connectionCodeSigningValidationSkipped = NO; #endif - // It's safe to allow any connections once stage 1 installation is complete + // It's safe to allow any connections once stage 1 installation is complete and appcast data has been received. // This is to allow general updaters to resume the installation. - if (!_performedStage1Installation) { + if (!_performedStage1Installation || !_receivedAppcastItemData) { BOOL passesValidation; NSError *validationError = nil; SUValidateConnectionStatus status = [SUCodeSigningVerifier validateConnection:newConnection error:&validationError]; @@ -597,6 +598,10 @@ - (void)handleMessageWithIdentifier:(int32_t)identifier data:(NSData *)data [self extractAndInstallUpdate]; }); } else if (identifier == SPUSentUpdateAppcastItemData) { + os_unfair_lock_lock(&_newConnectionLock); + _receivedAppcastItemData = YES; + os_unfair_lock_unlock(&_newConnectionLock); + SUAppcastItem *updateItem = (data != nil) ? (SUAppcastItem *)SPUUnarchiveRootObjectSecurely(data, [SUAppcastItem class]) : nil; if (updateItem != nil) { SPUInstallationInfo *installationInfo = [[SPUInstallationInfo alloc] initWithAppcastItem:updateItem];
113279a21f75Improve synchronization of _receivedAppcastItemData (#2877)
2 files changed · +12 −10
Autoupdate/AppInstaller.m+11 −9 modified@@ -599,18 +599,20 @@ - (void)handleMessageWithIdentifier:(int32_t)identifier data:(NSData *)data }); } else if (identifier == SPUSentUpdateAppcastItemData) { os_unfair_lock_lock(&_newConnectionLock); - _receivedAppcastItemData = YES; - os_unfair_lock_unlock(&_newConnectionLock); - - SUAppcastItem *updateItem = (data != nil) ? (SUAppcastItem *)SPUUnarchiveRootObjectSecurely(data, [SUAppcastItem class]) : nil; - if (updateItem != nil) { - SPUInstallationInfo *installationInfo = [[SPUInstallationInfo alloc] initWithAppcastItem:updateItem]; + if (!_receivedAppcastItemData) { + _receivedAppcastItemData = YES; - NSData *archivedData = SPUArchiveRootObjectSecurely(installationInfo); - if (archivedData != nil) { - [_agentConnection.agent registerInstallationInfoData:archivedData]; + SUAppcastItem *updateItem = (data != nil) ? (SUAppcastItem *)SPUUnarchiveRootObjectSecurely(data, [SUAppcastItem class]) : nil; + if (updateItem != nil) { + SPUInstallationInfo *installationInfo = [[SPUInstallationInfo alloc] initWithAppcastItem:updateItem]; + + NSData *archivedData = SPUArchiveRootObjectSecurely(installationInfo); + if (archivedData != nil) { + [_agentConnection.agent registerInstallationInfoData:archivedData]; + } } } + os_unfair_lock_unlock(&_newConnectionLock); } else if (identifier == SPUResumeInstallationToStage2 && data.length == sizeof(uint8_t) * 2) { // Because anyone can ask us to resume the installation, it may be wise to think about backwards compatibility here if IPC changes uint8_t relaunch = *((const uint8_t *)data.bytes);
CHANGELOG+1 −1 modified@@ -4,7 +4,7 @@ * Polish and update Spanish translations to be gender neutral (#2874, #2875) (Emilio P Egido) * Guard against NULL CFRelease() on failure condition in fallback path (#2867) (Zorg) * Guard against symlinks when applying delta update files (fe7b718) (Zorg, fg0x0) -* Enforce connection to installer to be validated before receiving appcast item data (#2876) (Zorg, fg0x0) +* Enforce connection to installer to be validated before receiving appcast item data (#2876, #2877) (Zorg, fg0x0) # 2.9.1
1520cda1bda6Guard against NULL CFRelease() on failure condition in fallback path (#2867)
1 file changed · +3 −1
Autoupdate/SUCodeSigningVerifier.m+3 −1 modified@@ -471,7 +471,9 @@ + (SUValidateConnectionStatus)validateConnection:(NSXPCConnection *)connection e SecCodeRef code = NULL; OSStatus result = SecCodeCopyGuestWithAttributes(NULL, (__bridge CFDictionaryRef _Nullable)(attributes), kSecCSDefaultFlags, &code); if (result != errSecSuccess) { - CFRelease(code); + if (code != NULL) { + CFRelease(code); + } if (error != NULL) { *error = [NSError errorWithDomain:SUSparkleErrorDomain code:SUInsufficientSigningError userInfo:@{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"The client connection could not be validated because SecCodeCopyGuestWithAttributes() failed with error %d", result] }];
Vulnerability mechanics
Root cause
"Missing code-signing validation on XPC connections accepted after stage 1 installation completes, allowing unvalidated local processes to inject spoofed appcast item data."
Attack vector
A local attacker connects to the `<bundleId>-spki` Mach service after stage 1 installation completes but before the installer's connection is invalidated. Because `shouldAcceptNewConnection:` skips `SUCodeSigningVerifier validateConnection:` once `_performedStage1Installation` is `YES` [patch_id=3106496], the attacker can send a spoofed `SPUSentUpdateAppcastItemData` message containing a crafted `SUAppcastItem`. The progress agent re-broadcasts the forged item on its status service, causing other Sparkle-aware clients to display attacker-controlled release notes (name, version, critical flag). In the system-domain case the Mach service runs as root and is reachable by any local user process.
Affected code
`Autoupdate/AppInstaller.m`'s `shouldAcceptNewConnection:` and `handleMessageWithIdentifier:` methods. The vulnerability is in the XPC listener logic that skips code-signing validation after `_performedStage1Installation` is set, and in the lack of a `_receivedAppcastItemData` guard to prevent spoofed `SPUSentUpdateAppcastItemData` messages from unvalidated connections.
What the fix does
Patch [patch_id=3106496] introduces a `_receivedAppcastItemData` boolean that is set to `YES` only when the installer processes a legitimate `SPUSentUpdateAppcastItemData` message. The `shouldAcceptNewConnection:` method now requires both `_performedStage1Installation` AND `_receivedAppcastItemData` to be true before skipping code-signing validation, preventing unvalidated connections from injecting spoofed appcast data. Patch [patch_id=3106494] wraps the flag check and the data processing inside the same `os_unfair_lock` critical section, eliminating a race condition where a second concurrent message could bypass the guard.
Preconditions
- authThe attacker must be a local process on the same macOS system.
- configStage 1 installation must have completed (_performedStage1Installation = YES) but the legitimate appcast item data must not yet have been received (_receivedAppcastItemData = NO).
- networkThe attacker must connect to the -spki Mach service before the installer's connection is invalidated.
- inputThe attacker sends a crafted SPUSentUpdateAppcastItemData message containing a spoofed SUAppcastItem.
Generated on May 29, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
2News mentions
0No linked articles in our index yet.