Feather: Arbitrary File Write via the Unconfirmed `feather://install/` Deep Link
A single feather://install/ deep link makes Feather unpack an archive without confirmation and overwrite files in Documents/ and Library/ via path traversal.
Advisory ID: TP-2026-077
Product: Feather (sideloader for iOS and macOS apps)
Vulnerability type: Path traversal / arbitrary file write (CWE-22, CWE-1395)
CVE: not requested
CVSS: Moderate (vendor rating, no vector published)
Affected versions: <= 2.9.0
Status: Published by the vendor; no fixed version designated (mitigation: pin marmelroy/Zip to commit 6940cebe)
Vendor advisory: GHSA-r8pm-8xc6-rwhq
Reported: 15 August 2026
Summary
Feather is a sideloader for iOS and macOS apps. The deep link feather://install/<https-url> triggers a download with no in-app confirmation, whose archive is then unpacked with Zip.unzipFile(..., overwrite: true). The pinned Zip library marmelroy/Zip 2.1.2 does not check entry names for traversal, so ../../ reaches Documents/ and Library/ from the working directory. With a single deep link an attacker overwrites critical files, such as the install server's TLS certificate or the app database, which disables the service and deletes the user's Apple signing identities. turingpoint verified the flow and reported it responsibly.
Root cause
FeatherApp.swift:125-129 passes feather://install/<https-url> straight to DownloadManager.startDownload(from:) with no in-app confirmation. The finished download goes through DownloadManager.swift:210 to FR.handlePackageFile and reaches AppFileHandler.extract() (FR.swift:26), which calls Zip.unzipFile(..., overwrite: true) (AppFileHandler.swift:63). The pinned marmelroy/Zip 2.1.2 joins the raw entry name via appendingPathComponent (Zip/Zip.swift:179), creates missing parent directories (:200), and writes via fopen(fullPath,"wb") (:210) with no traversal check. The working directory <container>/tmp/FeatherImport_<uuid>/ sits exactly two levels below the container root, so ../../ reaches Documents/ and Library/; the only check on the path is a hasPrefix("https://") (URL+validateScheme.swift:14) with no host allowlist. The import reports success and does not roll back a traversal-only archive, so overwritten files such as Documents/server.pem or Feather.sqlite silently take the install server offline and, via _destroyStore, delete the signing identities in Documents/Certificates.
Proof of Concept
Schematically, a single deep link:
feather://install/https://<attacker-host>/pkg.zip
pkg.zip contains an entry with a traversal name, e.g. ../../Documents/server.pem
-> downloaded and unpacked with no confirmation; the written path leaves the
working directory and overwrites files in Documents/ or Library/.
Because no confirmation precedes extraction and the Zip library does not check entry names, a ../../ entry leaves the working directory; the import still reports success.
Impact
- Overwriting arbitrary files in the app container's
Documents/andLibrary/with a single deep link. - Silent, persistent failure of the install server through a destroyed TLS certificate (
server.pem). - Deletion of the user's Apple signing identities via the error handling of the corrupted app database.
- Redirection of the
itms-services://manifest through overwritten certificate files.
References
Is Something Like This in Your Software?
Our team found this vulnerability in the course of its work. Have your applications tested by the same specialists, with a penetration test from turingpoint.
