CVE-2025-65843 - Acustica Audio - Insecure File Handling via Symlink in Aquarius Desktop macOS
Note: No exploit code is released publicly, and the intent of this publication is to promote remediation and improve the security posture of the affected software. This disclosure follows the 90-day industry-standard timeline for responsible reporting. Want the details? Keep scrolling. The full timeline and contact history are available further down the page.
CVE ID: CVE-2025-65843
Title: Aquarius Desktop Insecure File Handling via Symlink Dereference in Support Archive Generation
Affected Product: Aquarius Desktop for macOS 3.0.069
Affected Component: Support archive generation (SupportTab::prepareSupportArchive()); JUCE RangedDirectoryIterator with followSymlinks=true; log handling in ~/Library/Logs/Aquarius
Vulnerability Type: Directory Traversal / Insecure File Handling
Attack Type: Local
Impact: Information Disclosure; Arbitrary File Inclusion; Privilege Escalation (when chained with CVE-2025-65842)
Summary
Aquarius Desktop 3.0.069 follows symbolic links during the creation of support archives. The JUCE directory iterator is configured with followSymlinks=true, and file output operations do not use O_NOFOLLOW, allowing symlinks placed inside ~/Library/Logs/Aquarius to be dereferenced as normal files.
A local attacker can plant symlinks targeting arbitrary filesystem paths (e.g., /etc/passwd, user Keychain DB, or root-owned locations). When a user generates a support archive, Aquarius reads or writes through these symlinks, leading to unauthorized disclosure or modification of sensitive files. When combined with the HelperTool privilege escalation flaw (CVE-2025-65842), this can expose or overwrite root-owned files.
Introduction
Welcome back!
This is post 3 of 3 in my security review of the Aquarius Desktop application.
After finding the local privilege escalation in the HelperTool service and a weak-encryption credential flaw in aquarius.settings, I shifted my attention to another part of the application’s design: how Aquarius handles logs, diagnostics, and its “Create support data file” feature.
What I found was another security issue and this time concerned the filesystem.
In this third and final part of my analysis, I discovered that Aquarius Desktop blindly follows symbolic links inside its log directory (~/Library/Logs/Aquarius). Because these paths are never validated, an attacker can plant a malicious symlink and coerce the application into reading any file on the system and bundling it into the support ZIP archive. This turns a routine diagnostic feature into a file exfiltration vector.
Although this behavior was likely implemented to simplify debugging and support workflows, the lack of path sanitization introduces a local security risk. In this post, I’ll walk through how the vulnerability works, how it can be exploited in practice, and what changes Acustica can make to harden the application without disrupting support operations.
Vulnerability Overview
The application have this feature called “Create support data file”. This feature mechanism bundles logs and diagnostic files into a ZIP archive before sending them to Acustica support in case it’s requested by them.
The problem with this feature is that Aquarius Desktop blindly follows symbolic links (symlinks) inside its log directory and includes whatever they point to in the generated support archive. Combined with the fact that the application writes ZIP files without using O_NOFOLLOW, this creates a symlink traversal and data exfiltration path.
Let’s go through the flow:
Log Folder Resolution
The base log directory is obtained through juce::FileLogger::getSystemLogFileFolder, which hardcodes the path to the user’s logs folder:
void juce::FileLogger::getSystemLogFileFolder(undefined8 *param_1)
{
// Construct base path string "~/Library/Logs"
*local_28 = 0x72617262694c2f7e; // "~ / L i b r a r"
*(int *)(puVar2 + 3) = 0x6f4c2f79; // "y / L o"
*(undefined2 *)((long)puVar2 + 0x1c) = 0x7367; // "g s"
*(undefined1 *)((long)puVar2 + 0x1e) = 0;
// Parse the absolute path into a juce::File
juce::File::parseAbsolutePath(param_1, &local_28);
}
This confirms that Aquarius directly targets ~/Library/Logs as the root location for logs to include in the support archive.
File Enumeration with Symlink Following
Within SupportTab::prepareSupportArchive, Aquarius uses JUCE’s directory iterator to walk through log files:
// Ghidra decompile (~line 373)
juce::RangedDirectoryIterator iter(logDir, true, "*.log", 0);
The second argument (true) corresponds to JUCE’s followSymlinks parameter. This instructs the iterator to traverse symbolic links as though they were regular files. Any attacker‑controlled symlink planted inside ~/Library/Logs/Aquarius will be followed and resolved to its target, regardless of location or sensitivity.
File Inclusion into ZIP Archive
Files collected by the iterator are subsequently added to a support ZIP using juce::ZipFile::Builder:
// Multiple call sites in prepareSupportArchive()
juce::ZipFile::Builder::addFile(file, compressionLevel, relativePath);
Each File object is built from absolute paths parsed earlier with juce::File::parseAbsolutePath, which performs no checks against symlinks or device nodes.
ZIP Creation and Write Sink
When it’s time to finalize the archive, Aquarius writes the ZIP with JUCE’s FileOutputStream:
// Ghidra decompile (~line 363)
juce::FileOutputStream out(zipFile, 0x4000);
While this happens, JUCE invokes the macOS open() system call with flags like:
O_WRONLY | O_CREAT | O_TRUNC
The O_NOFOLLOW is not used. This means that if the output path is a symlink, the OS will transparently dereference it. Combined with symlink following during enumeration, this creates a lack of path validation. According to Apple’s documentation (FileDescriptor.OpenOptions.noFollow), this option make sure that open() fails if the target is a symbolic link. By default, Aquarius uses O_CREAT | O_WRONLY | O_TRUNC, which permits transparent symlink traversal.
Proof of Concept
To demonstrate the impact of the symlink vulnerability, I developed a simple PoC attack against the Aquarius Desktop application’s “Create support data file” feature. By abusing insecure log handling, the PoC shows that arbitrary files can be exfiltrated into the generated ZIP archive.
So first step is to prepare a “malicious” symlink.
I created a symbolic link inside Aquarius’s log directory pointing to a sensitive system file.
ln -s /etc/passwd ~/Users/[user]/Library/Logs/Aquarius/poc.log
Here, poc.log is a symlink to /etc/passwd
Next, it’s just a matter of clicking on the “Create support data file” feature in the application.
This calls SupportTab::prepareSupportArchive(), which collects log files from ~/Library/Logs/Aquarius and bundles them into a ZIP archive (AquariusSupport-2025-[DATE].zip).
Now, during the archive creation, the juce::RangedDirectoryIterator traverses the symlink (poc.log) and resolves it to /etc/passwd and juce::ZipFile::Builder::addFile() includes the dereferenced file in the archive.
The final ZIP archive, generated in Aquarius’s working directory, contains /etc/passwd under the name poc.log.
We can simply extract it:
unzip aquariusSupport-2025-[DATE].zip
cat Logs/poc.log
The fun part.
Assuming the attacker already gained a foothold via the HelperTool XPC service Privilege Escalation vulnerability, he can spawn an interactive shell by running python3 -c 'import pty; pty.spawn("/bin/bash")' and then navigate into the Aquarius log directory (~/Users/[user]/Library/Logs/Aquarius) and plant a malicious symbolic link pointing to a sensitive file such as /etc/passwd. When the victim subsequently triggers the “Create support data file” feature from the application’s Help menu, the vulnerable prepareSupportArchive() routine follows the attacker’s symlink and includes the contents of /etc/passwd inside the generated support ZIP. The attacker can then simply extract the archive and read the sensitive file under the attacker controlled name poc.log.
Reading the /etc/passwd file is as simple as running cat /Logs/poc.log
Remediation
There’s various ways that the Aquarius support archive feature can be hardened to prevent symlink abuse and arbitrary file disclosure.
- Disable Symlink Following using
juce::RangedDirectoryIteratorwithfollowSymlinks = falseto make sure that only real files are enumerated in the log directory. - Perform Path Validation before adding any file into the ZIP, validate it with
lstat() / fstat()to confirm it is a regular file (S_IFREG) located strictly within~/Library/Logs/Aquarius. - Reject symlinks, hardlinks, device nodes, or paths that escape the intended directory. Use
O_NOFOLLOWfor File Opens whereFileOutputStreamor equivalent APIs are used, open files withO_NOFOLLOW(Swift:.noFollow) to prevent transparent dereferencing of symlinks. Apple’s documentation explicitly recommends this for secure file operations. - Limit the support ZIP contents to a fixed allowlist of expected log files, rather than zipping the entire directory. This prevents attackers from introducing unexpected files or symlinks
- Add a warning to the user when the support archive contains unexpected or non‑standard files.
Disclosure timeline
| Date | Action |
|---|---|
| August 2, 2025 | Vulnerability discovered during local security analysis of Aquarius Desktop and its helper components. |
| August 3–5, 2025 | Initial technical validation and proof-of-concept developed confirming local privilege escalation via the HelperTool XPC service. |
| August 7, 2025 | Full vulnerability report prepared, including reproduction steps and secure remediation guidance. |
| August 19, 2025 | Responsible disclosure email sent to Acustica Audio with attached reports and researcher PGP key requesting a secure communication channel. |
| August 23, 2025 | No acknowledgment received from the vendor; follow-up email sent. |
| November 13, 2025 | Escalation attempt submitted to MITRE CVE Program for coordination assistance. |
| November 19, 2025 | No vendor response received; proceeding with public disclosure in accordance with a 90-day coordinated disclosure policy. |
| November 28, 2025 | CNA response received. CVE ID reserved: CVE-2025-65843 |