
Cloud Vulnerability DB
A community-led vulnerabilities database
CVE-2026-47121 is a binary delta apply intermediate-symlink traversal vulnerability in the Sparkle software update framework for macOS. It affects all Sparkle versions up to and including 2.9.1 (both the 1.x master branch and the 2.x branch). The vulnerability was published to the GitHub Advisory Database on May 29, 2026, and assigned CVE ID CVE-2026-47121. It carries a CVSS v3.1 base score of 6.1 (Moderate) (Github Advisory, Sparkle Advisory).
The root cause is a combination of CWE-22 (Path Traversal) and CWE-59 (Improper Link Resolution Before File Access / Link Following) in two source files. In Autoupdate/SPUSparkleDeltaArchive.m, the extractItem: method creates symlinks from archive content verbatim — accepting absolute paths and .. targets — without validating the symlink destination. In Autoupdate/SUBinaryDeltaApply.m, the parent-directory symlink check only inspects the immediate parent of the destination path (one level up) rather than walking all intermediate path components; additionally, the check is skipped entirely when attributesOfItemAtPath: returns nil (i.e., when the parent does not yet exist). An attacker crafts a malicious .delta archive with two items: the first creates a symlink inside the destination tree pointing to an arbitrary directory (e.g., /Library/LaunchDaemons), and the second extracts a regular file through that symlink path. Because fopen(path, "wb") follows intermediate symlinks at the kernel level, the file is written to the resolved external path. Exploitation requires the malicious .delta to pass EdDSA signature verification, meaning the attacker must possess the developer's private signing key (Sparkle Advisory, Github Advisory).
The primary impact is arbitrary file write at the privilege level of the AppInstaller process. For system-domain installs (where AppInstaller runs as root), this enables writing files to any location on the filesystem — including /Library/LaunchDaemons, /etc/, and /usr/local/ — allowing an attacker to establish persistent root-level code execution (e.g., by dropping a LaunchDaemon plist). For user-domain installs, the same technique can write to user-writable directories such as ~/Library/LaunchAgents/, enabling user-level persistence. This is a defense-in-depth gap: it grants a strictly broader write primitive than the "replace the app bundle" capability that a stolen signing key already provides, with no confidentiality or availability impact beyond the integrity violation (Sparkle Advisory).
A proof-of-concept (PoC) is publicly documented in the GitHub Security Advisory, detailing the exact archive structure and item sequence required to trigger the traversal. The NVD SSVC assessment classifies exploitation as "poc" and "not automatable," reflecting the high-complexity prerequisite of EdDSA private-key compromise. The EPSS score is approximately 0.029% (0.000290), indicating a low near-term exploitation probability. There is no evidence of in-the-wild exploitation, no known threat actor attribution, and the vulnerability is not listed in the CISA KEV catalog (Github Advisory, Sparkle Advisory).
.delta will fail signature verification and be rejected..delta archive: Using the SPUSparkleDeltaArchive writer or by hand-assembling the archive format, construct a delta with two items in order:relativeFilePath = "Contents/Resources/escape", commands = SPUDeltaItemCommandExtract (0x02), mode = S_IFLNK | 0o755 (0xA1ED), payload = "/Library/LaunchDaemons" (or another target directory).relativeFilePath = "Contents/Resources/escape/com.attacker.persistence.plist", commands = SPUDeltaItemCommandExtract (0x02), mode = S_IFREG | 0o644 (0x81A4), payload = <attacker-chosen LaunchDaemon plist bytes>.sparkle:edSignature attribute, and host it on an attacker-controlled update feed that the target Sparkle host is pointed at.applyBinaryDelta enumerates items; Item 1 passes the .. check (no .. in path components) and the shallow parent-symlink check, then extractItem: creates Contents/Resources/escape -> /Library/LaunchDaemons.Contents/Resources/escape resolves through the newly created symlink to /Library/LaunchDaemons; attributesOfItemAtPath: returns NSFileTypeDirectory (not symlink), so the check passes. fopen("Contents/Resources/escape/com.attacker.persistence.plist", "wb") causes the kernel to resolve the symlink and write /Library/LaunchDaemons/com.attacker.persistence.plist.finalDestination, so the post-apply hash check passes (or the file persists even if the hash fails, since cleanup only removes finalDestination). On next reboot, macOS launches the attacker's daemon as root (Sparkle Advisory)..plist files in /Library/LaunchDaemons/ or ~/Library/LaunchAgents/ not associated with any known installed application; new symlinks inside application bundle directories (e.g., Contents/Resources/escape) pointing to system directories such as /Library/LaunchDaemons, /etc/, or /usr/local/./usr/local/, /etc/ subdirectories, or other system-owned paths with timestamps coinciding with a Sparkle update event./var/log/system.log or unified logging via log show) showing launchd loading a previously unknown daemon from /Library/LaunchDaemons/ after a reboot; Sparkle update logs recording a delta apply operation immediately before the anomalous file creation.launchd referencing a plist not present before the last Sparkle update cycle; child processes of the Sparkle AppInstaller writing files outside the target application bundle directory..delta) file downloads from domains not matching the legitimate software vendor (Sparkle Advisory).Upgrade to Sparkle version 2.9.2, which contains the patch. The fix modifies SUBinaryDeltaApply.m to walk every intermediate path component of relativePath using lstat() and reject the operation if any component is a symbolic link, rather than only checking the immediate parent directory. No configuration-based workaround is available; the only remediation is upgrading to 2.9.2. Developers embedding Sparkle in their macOS applications should rebuild and redistribute their applications with the patched framework version (Github Advisory, Patch Commit).
Source: This report was generated using AI
Free Vulnerability Assessment
Evaluate your cloud security practices across 9 security domains to benchmark your risk level and identify gaps in your defenses.
Get a personalized demo
"Best User Experience I have ever seen, provides full visibility to cloud workloads."
"Wiz provides a single pane of glass to see what is going on in our cloud environments."
"We know that if Wiz identifies something as critical, it actually is."