Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
cve-2026-43687 — Reverse engineering notes and a self-contained PoC for the macOS NFS client access-cache race (CVE-2026-43687), with kext disassembly diff and dtrace race capture. | Kitploit
Tools/GitHubGitHub/jvidhan/cve-2026-43687
Memory ForensicsVulnerability AnalysisExploitationReverse EngineeringBinary AnalysisPapers & ResearchLearning & Education
GitHubjvidhan/cve-2026-43687

cve-2026-43687

Reverse engineering notes and a self-contained PoC for the macOS NFS client access-cache race (CVE-2026-43687), with kext disassembly diff and dtrace race capture.

View Repository
9h 59m agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2026-43687 — Reverse engineering notes and reproduction

Independent reverse engineering of the macOS NFS client access-cache race (CVE-2026-43687), plus a working PoC that triggers the race and captures it live with dtrace.

The bug is an unsynchronized read of the nfsnode access-cache pointer in _nfs_vnop_access. A malicious NFSv3 server can drive the access cache to reallocate while another thread is reading it, producing a kernel memory disclosure that a hostile server can influence. macOS 26.7 fixes this by inserting an lck_rw_t at nfsnode+0x158 and taking it shared around the cache read.


CVE at a glance

FieldValue
CVECVE-2026-43687
Componentcom.apple.filesystems.nfs (_nfs_vnop_access)
AffectedmacOS Tahoe 26.6 and earlier, iOS 26.x and earlier
Patched inmacOS Tahoe 26.7, macOS Golden Gate 27, iOS 26.7, iOS 27
Advisory impact"Connecting to a malicious NFS server may disclose kernel memory."
CVSS v3.16.5 (Medium) — AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N
Reported byR4mbb of KRsecurity and Peter Malone (per Apple's advisory)

Why this writeup exists

Apple's advisory for CVE-2026-43687 documents the impact and the patch version. It does not document the technical mechanism:

  • Which field in the nfsnode is raced
  • Where the second read happens
  • Why the fix inserts a lock at that specific offset
  • Why the PoC must use access(2) rather than stat(2)
  • Why some NFSv3 reply shapes silently break the mount even when the wire format is nearly correct

No public technical writeup was found at the time of writing. This repository fills that gap with an independent reverse engineering analysis of the NFS kext between 26.6 and 26.7, and a working PoC that reproduces the race on a live target.

This is not a discovery claim. The CVE was reported by R4mbb and Peter Malone and patched by Apple. The contribution here is the technical analysis and the reproduction.


Summary of the vulnerability

_nfs_vnop_access in the NFS client reads nfsnode+0x158 — the pointer to the per-UID access-cache array — twice inside a single call, without holding any lock:

root@kitploit:~
; macOS 26.6, com.apple.filesystems.nfs
fffffe000b52def4   ldr  w8,  [x20, #0x160]     ; count
fffffe000b52def8   cmp  w23, w8
fffffe000b52defc   b.ge ...
fffffe000b52df00   ldr  x8,  [x20, #0x158]     ; cache ptr (read #1)
...
fffffe000b52df98   ldr  x8,  [x20, #0x158]     ; cache ptr (read #2)
fffffe000b52dfb0   ldr  w21, [x9]              ; dereference

The writer, _nfs_nget, reallocates the array with kalloc_data and stores the result at +0x158 whenever the client sees a new UID from the server:

root@kitploit:~
fffffe000b52100c   bl   0xfffffe000b6a1dd8    ; kalloc
fffffe000b521010   str  x0,  [x22, #0x158]    ; cache ptr
fffffe000b521018   str  w20, [x22, #0x160]    ; cache count

If another thread reaches _nfs_nget on the same nfsnode between the reader's two loads, the second load returns the new pointer while the first read — already used to compute an offset — was based on the old one. The subsequent dereference reads from freed kernel heap.

The 26.7 fix:

root@kitploit:~
fffffe000b9e3064   str  x0,  [x22, #0x168]    ; cache ptr moved
fffffe000b9e306c   str  w28, [x22, #0x170]    ; cache count moved
fffffe000b9e307c   add  x0,  x22, #0x158      ; lock slot
fffffe000b9e3084   bl   _lck_rw_init          ; init RW lock

and in _nfs_vnop_access:

root@kitploit:~
fffffe000b9f0200   add  x0,  x20, #0x158
fffffe000b9f0204   bl   _lck_rw_lock_shared    ; take the lock
fffffe000b9f0208   ldr  x9,  [x20, #0x168]    ; cache pointer
...
fffffe000b9f0230   bl   _lck_rw_unlock_shared  ; release the lock

Struct layout change:


What this repository contains

Reverse engineering

  • Disassembly diff of _nfs_nget and _nfs_vnop_access between the 26.6 and 26.7 NFS kexts — see docs/PATCH_DIFF.md
  • Identification of the raced field: nfsnode+0x158 in 26.6
  • Identification of the fix: lck_rw_t inserted at +0x158, cache pointer moved to +0x168, lck_rw_lock_shared taken around the read
  • Syscall analysis: access(2) enters _nfs_vnop_access; stat(2) goes through _nfs_getattr and never reaches the vulnerable function
  • Runtime confirmation of the race with dtrace, capturing the cache pointer changing mid-call

See docs/ANALYSIS.md for the full writeup and docs/ARTIFACTS.md for addresses and log samples.

Reproduction

  • poc.sh — a single-file, self-contained PoC:
    1. Stops Apple's nfsd to free port 2049
    2. Starts a malicious NFSv3 server on 127.0.0.1 that rotates the reported UID in every reply
    3. Mounts the export on a fresh mountpoint with noac
    4. Spawns a per-user hammer issuing access(2) via test -r / test -w
    5. Attaches a dtrace probe to nfs_vnop_access, recording any call where nfsnode+0x158 changes mid-call
    6. Prints a summary with the race count

What this PoC demonstrates

  • A malicious NFSv3 server rotating the UID it reports on every reply
  • The victim's kernel reallocating the access-cache array in response
  • The unsynchronized read in _nfs_vnop_access observing the array change during a single call
  • Live capture of that interleaving via dtrace

What this PoC does NOT demonstrate

  • A byte-level kernel memory leak visible to the attacker
  • Code execution, privilege escalation, or a shell on the victim

The race is the precondition for the disclosure. To turn the race into an actual leak, an attacker would need to observe the reader using the stale pointer and propagate those bytes somewhere they can read. On arm64e, the value at nfsnode+0x158 is PAC-signed and the per-boot key is not available from userland, so dtrace alone can observe the race but cannot decode the pointer. See the "Paths tested and ruled out" section in docs/ANALYSIS.md.

The demonstrated impact is the race itself — the exact window that the 26.7 RW-lock fix closes.


Requirements

Target (victim) host

  • macOS 26.6 or earlier (vulnerable kernel)
  • dtrace available (may require SIP adjustment on some installs)
  • python3, dscl, mount
  • Root

No separate attacker host needed

The PoC runs entirely on the target. The malicious NFS server binds to 127.0.0.1 and the mount is over loopback. This keeps the PoC self-contained and reproducible without network configuration.


Usage

root@kitploit:~
chmod +x poc.sh
sudo ./poc.sh

Optional tuning via environment variables:

root@kitploit:~
sudo HAMMER_COUNT=30 RUN_SECONDS=600 ./poc.sh

HAMMER_COUNT sets the number of per-user hammer threads (uses whatever nfsuserNNN accounts exist, creating them as needed). RUN_SECONDS sets the dtrace window.

Expected output

root@kitploit:~
[*] ensuring nfsuser accounts exist (UID 201..240)
    nfsuser accounts available: 12
[*] starting evil NFS server on 127.0.0.1:2049
[*] mounting /Users/Shared/nfs_test (with noac)
    mount check: hello.txt statable
[*] spawning up to 12 per-user threads + 1 root loop
    started 12 user threads + 1 root loop
[*] running dtrace for 180s — looking for RACE lines
[*] stopping dtrace
[*] cleaning up

=================== SUMMARY ===================
RACE events caught: 16

Vulnerable interleaving observed — sample:
RACE nd=fffffe5f53cbb940 in=(0,0) out=(b0967e0023297878,0)
RACE nd=fffffe5f534db940 in=(0,0) out=(84dd7e0023297878,0)
RACE nd=fffffe5f53cbb940 in=(0,0) out=(c9a37e0023297878,0)
RACE nd=fffffe5f538ab940 in=(0,0) out=(1867e0023297878,0)
RACE nd=fffffe5f539db940 in=(0,0) out=(149bfe0023297878,0)

CVE-2026-43687 trigger SUCCESSFUL
===============================================

Each RACE line is one call of nfs_vnop_access where the access-cache pointer changed mid-call.

Verification of the patch

On a patched system (26.7 / 27), the same workload produces zero RACE events. See docs/PATCH_DIFF.md for the disassembly comparison.


NFSv3 server gotchas (for reproducibility)

Two bugs in the PoC's server were fixed during development and are documented here so others building similar tooling don't hit them:

  1. ACCESS3resok requires post_op_attr, not fattr3. RFC 1813 defines the reply as post_op_attr obj_attributes; uint32 access;. post_op_attr includes a bool prefix before the fattr3. Omitting that bool makes the reply 4 bytes short; the client silently rejects it and the mount never becomes usable.

  2. LOOKUP for AppleDouble names (._*) must return NFS3ERR_NOENT (2), not NFS3ERR_STALE (70). macOS probes for ._<name> sidecars during normal path resolution. Returning STALE poisons the mount.

Both are documented in docs/ANALYSIS.md.


A note on the runtime value

The out values in the RACE output have a constant low-48-bit pattern (...7e0023297878) across different nfsnodes, varying only in the high 16 bits. That confirms the field is PAC-signed or obfuscated, not a raw kernel pointer. You can observe the state transition (NULL → populated) from userland, but you cannot decode or dereference the pointer without the kernel's per-boot PAC key.

For the same reason, symbolication against the KDK is not useful for these values — they aren't text-relative addresses.


Credits

  • Original discovery: R4mbb of KRsecurity and Peter Malone, per the Apple security advisory for CVE-2026-43687.
  • Independent analysis and PoC: jvidhan
  • Reference: Apple's advisory and the patched binary served as the baseline for comparison with the vulnerable version. The KDK for macOS 26.6 (build 25G72) provided symbols for the kernel-side analysis.

Disclaimer

This repository is provided for defensive security research and education only.

  • It is intended for use against systems you own or have explicit written permission to test.
  • Using this tool against systems you do not own or control may violate local, national, or international law.
  • The author(s) assume no responsibility or liability for any misuse or damage caused by this code.
  • The PoC is limited to demonstrating a kernel race. It does not achieve code execution, privilege escalation, or a byte-level memory leak. Any claims of RCE or full memory disclosure from this PoC are unsupported by the included analysis.
  • Apple, macOS, XNU, NFS, autofs, and automountd are trademarks of Apple Inc. This project is not affiliated with or endorsed by Apple.

License

MIT. See LICENSE.

Download Tool
OffsetmacOS 26.6macOS 26.7
+0x158cache array pointerlck_rw_t
+0x160cache count(part of lock)
+0x168(other)cache array pointer
+0x170(other)cache count