Skip to content

How a single PostScript file leaks your Mac's memory

Csaba Fitzl Csaba Fitzl
How a single PostScript file leaks your Mac's memory

When I started my InfoSec journey, most of the offensive classes I took focused on memory corruption exploits. I learned a lot about buffer overflows, DEP and ASLR bypasses, and even got into kernel exploitation. However, since my job at that time was mostly hunting for bad guys in an insane amount of logs and telemetry data, I never really had the time to apply this knowledge.

About 8 years ago, I started learning about macOS, and from the beginning I approached it via logic bugs, starting with simple things such as dylib hijacking. Years went by, I started to really enjoy looking for these kinds of vulnerabilities, and slowly I drifted further and further away from memory corruption work.

Then I read the following in Jonathan Levin's OS Internals books, about Spotlight and QuickLook plugins: "Plugins, however, involve a potential security risk: File formats can be malformed in a nigh infinite number of ways, and targeted malformations could lead to code execution.

It sounded interesting, so I saved it to the very bottom of my to-do list, thinking that maybe, someday, I should try fuzzing some file types. But I hate fuzzing, that is not the way I like to work, and I never got to this. Time passed, and the idea stayed in the back of my mind, but I knew I’d probably never get to this.

Then 2026 came, and by now AI has advanced so much in vulnerability research that it's impossible to ignore. It's everywhere. You can read about people using it for their own research, how Claude finds tons of bugs, and how it can find vulnerabilities just by asking it, without any hints. I also use AI as part of my research work, and it definitely speeds things up.

One day I decided to run a short side quest. I dusted off this old idea about file parser vulnerabilities, uploaded some decompiled functions from the PostScript Spotlight plugin, and gave Claude the following complex prompt:

Can you find any potential memory corruption issues in this ps file parser / spotlight plugin?

And it did.

The vulnerability

The vulnerability is in the Spotlight PostScript plugin. The PostScript file contains Document Structuring Conventions (DSC) headers, and the parser extracts metadata information from these such as version, creator, title, page count, and bounding box dimensions. These fields are stored in the Spotlight index and become queryable through mdls, mdfind, and the MDItem API later. A header like this looks like.

%!PS-Adobe-2.0

%%Creator: Iru Inc

%%Title: iru.ps

%%Pages: 1

%%BoundingBox: 0 0 612 792

The issue is within the function _GetMetadataForFile, which is the standard function name in older Spotlight importers. It reads the first 4000 bytes (0xFA0) of the target file into a heap-allocated buffer:

__nitems = min(file_size, 0xFA0);  // cap at 4000

x0_5 = malloc(__nitems);

fread(x0_5, 1, __nitems, stream);

x28_1 = &x0_5[__nitems]; // buffer end pointer

Next, the function uses strnstr(buffer, keyword, __nitems) (wrapped in _OUTLINED_FUNCTION_4) to locate each DSC comment keyword within the buffer.

After locating a DSC keyword, the code scans forward byte-by-byte from the end of the keyword to find the end of the value (the first byte < 0x20, i.e., a control character such as newline, null, or tab). There are three different scanning loop variants used across the four DSC keywords each behaving slightly differently, though all of them are vulnerable. We'll focus here on just one, since it allows most bytes to be leaked.

The %%Creator: scanning loop (binary offsets 0xB44–0xB6C) and %%Title: scanning loop (binary offsets 0xBB8–0xBD0) both use an incrementing counter; below is the loop for %%Title:.

x10_2 = &x0_5[__nitems] - x0_10 - 0xa; // starts POSITIVE

do {

byte = *(uint8_t*)scan_ptr;

scan_ptr++;



if (byte >= 0x20) {

z_3 = !x10_2; // true only when x10_2 == 0

} else {

z_3 = true; // control char → stop

}



x10_2 += 1; // INCREMENTS each iteration

end_ptr++;

} while (!z_3);

The counter x10_2 starts at a positive value and increments by 1 each iteration. It holds the offset for the data referenced by the %%Title: metadata in this case. The counter-based exit condition !x10_2 is true only when x10_2 == 0, which never happens, since the counter moves away from zero on every iteration. This means the loop can only terminate by encountering a byte less than 0x20.

There is no buffer bounds check in this loop variant. If the value portion of the DSC comment contains only printable characters (bytes ≥ 0x20) all the way to the buffer boundary, the loop crosses that boundary and continues scanning through adjacent heap memory indefinitely, until it finally hits a byte < 0x20.

This loop calculates the start and end of a string for the metadata we want to collect.

The pointer range accumulated by the scanning loop — potentially extending far past the buffer boundary — is passed to CFStringCreateWithBytes (via _OUTLINED_FUNCTION_0), creating a CFString that contains the out-of-bounds heap content. For the three string-valued metadata fields, this CFString is then written directly into the Spotlight metadata dictionary via CFDictionaryAddValue (wrapped in _OUTLINED_FUNCTION_3):

cf = CFStringCreateWithBytes(alloc, value_start, end_ptr - value_start, ...);

CFDictionaryAddValue(theDict, *kMDItemCreator, cf); // heap data persisted

The metadata is returned to the Spotlight indexing infrastructure and persisted to the on-disk index.

The exploit

An attacker needs a specially crafted .ps file to trigger the vulnerability. It must satisfy the following conditions.

1. The file is at least 4000 bytes (so __nitems = 0xFA0 and the large-file code path activates).

2. A DSC comment keyword (e.g., %%Creator:) appears somewhere in the first 4000 bytes.

3. The bytes following the keyword, up to byte 4000, contain no control characters (no newline, null, tab, or any byte < 0x20).

The keyword does not need to be near the end of the buffer. For example, %%Creator: at byte 50 followed by 3939 bytes of printable ASCII (no newline) before the 4000-byte boundary is sufficient. The scanning loop will consume all in-buffer bytes, cross the boundary, and continue through heap memory.

Spotlight importer plugins execute automatically via mdworker whenever a new file appears on the filesystem. No user interaction is required. Delivery methods that trigger indexing include: AirDrop file transfer, email attachment download, mounting a DMG or disk image, file sync via iCloud Drive or other cloud services, and files appearing in any Spotlight-indexed directory.

After indexing completes, the leaked heap data is persisted as file metadata and can be read via:

mdls -name kMDItemCreator /path/to/malicious.ps

mdls -name kMDItemTitle /path/to/malicious.ps

Or programmatically:

MDItemCopyAttribute(item, kMDItemCreator);

The mdworker process that runs the importer also processes other files concurrently. Its heap contains data from parsing other documents — file paths, text content, metadata from PDFs, emails, and other file types. The leaked bytes can therefore contain fragments of other files' content that were adjacent on the heap.

But there is more. Unless the unbound memory read hits a non allocated memory region, it will never crash the process, there won’t be any way to notice that this leak happened other then looking into the Spotlight database for weird stuff. We didn’t experiment a whole lot with this, but we could always leak some memory, most of the time a portion of a sandbox profile, this is shown below.

user@max ps % mdls output.ps

_kMDItemDisplayNameWithExtensions = "output.ps"

kMDItemCreator = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA



(...)

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA (allow file-read* file-write* (subpath (param "DARWIN_TEMP_DIR")))))"

kMDItemDateAdded = 2026-03-31 06:45:14 +0000

Disclosure and fix

Apple fixed this vulnerability quickly. We reported it in early April, and the fix was released by the end of July as part of macOS 26.6, assigned CVE-2026-43774. This was much faster than the usual turnaround time, though patching this kind of issue is also significantly easier than fixing complex logic bugs with corner-case race conditions. Here, a proper boundary check solves the problem.

I'll continue exploring logic bugs, but this was a nice detour. There are a few more Spotlight and QuickLook file parsers on the system, and it's likely worth focusing on these, since I'm sure there's more to be discovered.

You might ask why I'm not the one doing it? Simply because I'm putting my effort into other areas, and you can't have it all. That said, I think I can finally mark this long-outstanding task of finding file parser issues in Spotlight as COMPLETE.

Recent Articles

Featured image: Reliable Windows app patching with Iru system tray notifications
Lance Crandall 2 min read

Reliable Windows app patching with Iru system tray notifications

Notify Windows users when app updates are available. When your users are ready, they can allow Iru to close the app and update the application. Employees get more control over when updates land, and you spend less time chasing down unpatched devices.

Product News
Featured image: Iru Quarterly Threat Report: August 2026
Calvin So 5 min read

Iru Quarterly Threat Report: August 2026

EDR threat detections and responses Iru EDR is built to detect threats before they go mainstream. By combining behavioral detections with insights from our own malware research, we're able to protect customers from exploitation even before public disclosures or patches become available.

Threat Intelligence
Featured image: Feature engineering for a macOS malware classifier, and why the Mac makes it harder than Windows
Calvin So 13 min read

Feature engineering for a macOS malware classifier, and why the Mac makes it harder than Windows

The threat landscape for macOS malware is expanding, while the number of specialists dedicated to defending against it has not kept pace. Unlike Windows, where machine learning (ML) models are supported by extensive documentation and standardized datasets, the macOS environment presents a significant knowledge gap. At Iru, we captured SSTAR Agent, a crypto drainer targeting web3 technology developers via a fake interview lure, which we documented in an earlier post using an ML triage we built.

Threat Intelligence

See Iru in action

Discover why thousands of teams choose Iru

By submitting this form I agree to Iru’s Privacy Policy and consent to be contacted by Iru about its products and services.

Stay up to date

Iru's bi-weekly collection of articles, videos, and research to keep IT & Security teams ahead of the curve.