The asymmetric guard
CVE-2024-40843 patched a TOCTOU race in XProtectRemediatorGeneric. Two sibling remediators were missing the same guard. Binary analysis confirmed the asymmetry. Apple said not actionable — and on reflection, they were right.
When I ran the Oracle honeynet, the most instructive moments were the ones where the system behaved exactly as I expected — and I was still wrong about what I was seeing. A connection arriving at a port I had opened was not always what it appeared to be. The system was doing what it was designed to do; I had designed the wrong test. Watching a system behave as expected and watching it behave as you expected it to are different things. That distinction cost me two filings.
This is the story of XPR-0002 and XPR-0003: two submissions about sibling remediators in XProtect that were missing a lock guard present in their patched counterpart. The binary evidence was real and is verifiable today. The exploit claim was not demonstrated. Apple closed both as not actionable. After reviewing their response, I withdrew. They were right.
The background: CVE-2024-40843
CVE-2024-40843 patched a check-then-act race condition in XProtectRemediatorGeneric's removePlist() function. The pattern: the remediator checked whether a plist file existed, then later unlinked it. Between check and unlink, a symlink substitution could redirect the unlink to a different path — a classic TOCTOU race. The patch introduced a write-lock acquisition before the check-then-unlink sequence, closing the window.
The question I was asking when I examined the sibling remediators was straightforward: did the patch propagate to all remediators sharing the same removePlist() implementation? The answer, in the binary, was no.
Components: XProtectRemediatorCrapyrator, XProtectRemediatorToyDrop
Claim: Both remediators implement removePlist() without the write-lock guard introduced in CVE-2024-40843's patch to XProtectRemediatorGeneric. The asymmetry is verifiable by comparing symbol tables and disassembly across the three binaries.
Binary evidence: nm and disassembly confirm lock primitive present in patched Generic remediator; absent in Crapyrator and ToyDrop.
Apple's response: Not actionable. Both reports closed.
Outcome: I withdrew after reviewing Apple's response. Their assessment was correct.
The binary evidence
The structural difference between the patched and unpatched code paths is verifiable with standard tools. nm against the patched XProtectRemediatorGeneric binary shows lock primitives adjacent to the removePlist symbol. The same check against XProtectRemediatorCrapyrator and XProtectRemediatorToyDrop shows no corresponding lock primitive. The disassembly confirms it: in the patched binary, a lock acquisition precedes the check-then-unlink sequence; in the unpatched siblings, it does not.
This is not a subtle finding. The structural difference is clear. The asymmetric guard exists in the binary evidence, and anyone with access to the remediator binaries and a disassembler can confirm it today.
#!/bin/bash
# XProtectRemediator asymmetric guard analysis -- binary evidence only
# Demonstrates the structural difference; does NOT demonstrate exploitability
REMEDIATOR_PATH="/Library/Apple/System/Library/CoreServices/XProtect.bundle/Contents/MacOS"
echo "=== Checking for removePlist lock guard implementations ==="
for remediator in "$REMEDIATOR_PATH"/XProtectRemediator*; do
name=$(basename "$remediator")
# Check for write-lock pattern (guard present in patched remediators):
if nm "$remediator" 2>/dev/null | grep -q "os_unfair_lock\|pthread_mutex"; then
echo "[GUARDED] $name -- lock primitive present near removePlist"
else
echo "[UNGUARDED] $name -- no lock primitive found (asymmetric with patched siblings)"
fi
done
echo ""
echo "The asymmetric guard is a code-quality observation."
echo "It does not demonstrate that the race is exploitable."
echo "See also: 'The harness that lied' for why the runtime claim was withdrawn."
Why the claim was not demonstrated
The binary asymmetry is one thing. Demonstrating that the race in the unpatched remediators is actually winnable is another. XProtect remediators execute infrequently, on a schedule, and under conditions that are difficult to control from an attacker position. The window between check and unlink is real in the binary. Whether it is reachable under conditions that permit a symlink race requires a runtime demonstration — timing measurements, a triggering mechanism, and observed impact — that I did not produce.
A separate post, "The harness that lied", covers the test harness I built that appeared to confirm the exploit. It did not. The harness was measuring its own cleanup operations, not XProtect's behaviour. That failure was instructive and embarrassing in roughly equal measure.
The asymmetric guard is real and verifiable. Apple's closure was also correct. An asymmetric guard between sibling binaries is a code-quality issue — a maintenance inconsistency that could matter if a future change makes the unpatched path more accessible. But an asymmetric guard is not an exploitable race. The race in CVE-2024-40843 was exploitable because of specific conditions in XProtectRemediatorGeneric's execution context. Those conditions do not automatically apply to Crapyrator and ToyDrop. I confused "structurally similar code path" with "same exploitability". The binary evidence told me something. It did not tell me what I thought it told me. The honeynet lesson applied again: watching the system behave as expected — showing me an unguarded code path — was not the same as watching it behave as I expected it to, i.e., demonstrating that the race was winnable.
What to take from this
The binary analysis is worth doing. Asymmetric guards between sibling binaries are a legitimate finding class — they suggest that a fix was not propagated consistently, and they are worth reporting. The mistake was presenting the asymmetry as a demonstrated exploit rather than as a hypothesis to test. Apple's response was not dismissive; it was accurate. A code-quality observation without demonstrated impact is a different filing from a demonstrated exploit, and the two should not be submitted as if they were the same thing.
The distinction between the two is not a bureaucratic nicety. It is the difference between "this code path looks like it should be vulnerable" and "I have evidence that it is".
Disclosure note
XPR-0002 and XPR-0003 were submitted to Apple through the Apple Security Research Framework and closed as not actionable. I withdrew both after reviewing Apple's response. The binary analysis described here is reproducible against publicly available system binaries. No exploit was demonstrated. Apple's response is characterised accurately. This post is separate from "The harness that lied", which covers the methodology failure of the runtime test.
Are you there? The binary said something. Whether it said what I thought it said is a different question.