DEV Community

GUIDANCE WHITE
GUIDANCE WHITE

Posted on

SYSTEM Privilege Escalation via Forged IPC in Foxit PDF Reader's Update Service (CVE-2026-57239)

Overview

Field Value
CVE ID CVE-2026-57239
Type Local Privilege Escalation
CVSS 8.2 (High)
Affected Foxit PDF Reader/Editor 2026.1.1 and earlier, 14.0.4 and earlier, 13.2.4 and earlier (Windows)
Fixed in 2026.1.2 / 14.0.5 / 13.2.5
Discovered by Luke Paris (Paradoxis)
Disclosed 2026-07-15

CVE-2026-57239 lets a low-privileged Windows user who already has code execution escalate to NT AUTHORITY\SYSTEM. It isn't remote code execution — it's a post-exploitation privilege-escalation chain that turns "I can run code as a normal user" into "I own the box."

Three separate design flaws combine to make this work:

  1. A SYSTEM-level service trusts a user-writable file under ProgramData as its command channel.
  2. That file's IPC command is AES-128-CBC encrypted with a key hardcoded in the client binary, so anyone can forge a valid message.
  3. The process the service ultimately launches is vulnerable to DLL (or in this case, DRV) sideloading.

Chain all three together and a standard user reaches SYSTEM code execution.

1. The Target: FoxitPDFReaderUpdateService.exe

Foxit PDF Reader ships two related processes:

  • %APPDATA%\Foxit Software\Continuous\Addon\Foxit PDF Reader\FoxitPDFReaderUpdater.exe — the actual updater, running with the current user's privileges
  • FoxitPDFReaderUpdateService.exe — a background service running as NT AUTHORITY\SYSTEM

Watching this service in Procmon shows it repeatedly polling three files:

C:\ProgramData\Foxit Software\Foxit PDF Reader\Foxit Service\Log\log.lib
C:\ProgramData\Foxit Software\Foxit PDF Reader\FoxitData.txt
C:\Program Files\Foxit Software\Foxit PDF Reader\ProfStore\ProfStore.xml
Enter fullscreen mode Exit fullscreen mode

The Program Files path is off-limits to standard users. But C:\ProgramData\Foxit Software\Foxit PDF Reader\ is writable by the Users group by default — meaning any unprivileged process can freely create or modify FoxitData.txt.

Triggering an update check inside the Reader produces this event sequence:

  1. FoxitData.txt gets created/written
  2. %APPDATA%\...\FoxitPDFReaderUpdater.exe is launched
  3. That process runs as SYSTEM

In other words, whatever gets written to FoxitData.txt decides what the SYSTEM service executes, and with what arguments. The problem is how loosely that content is validated.

2. IPC Message Format: AES-128-CBC With a Hardcoded Key

Foxit's own logs (log.lib) capture both the plaintext command written into FoxitData.txt and the hex blob preceding it. The plaintext is a pipe (||) delimited list of key=value pairs:

sessionid=1||strTempUpdaterPath=C:\Users\User\AppData\Roaming\Foxit Software\Continuous\Addon\Foxit PDF Reader\FoxitPDFReaderUpdater.exe||csCommandLine= -updater -type "Auto Updater" -hwnd 131494 -bnoshowtip -readerpath "C:\Program Files\Foxit Software\Foxit PDF Reader\" -regpath "HKEY_CURRENT_USER\Software\Foxit Software\Foxit PDF Reader\Continuous" -version "2026.1.0.36452" -readerlang "en-US" -UpdateMode "1" -SessionID "1"
Enter fullscreen mode Exit fullscreen mode

Breaking down the fields:

  • sessionid — which Windows logon session (winlogon.exe) the SYSTEM service should associate the new process with
  • strTempUpdaterPath — the full path of the executable to run as SYSTEM
  • csCommandLine — the arguments passed to it

Reverse engineering FoxitPDFReaderUpdateService.exe reveals the key setup:

// FoxitPDFReaderUpdateService.exe (reconstructed from disassembly)
BYTE encryption_key[0x10];
memcpy(&encryption_key, "c6c7702dbcbf4678", 0x10u); // 16-byte hardcoded key
AES_SetKey(&aes_ctx, encryption_key, 128 /* bits */);
AES_CBC_Decrypt(&aes_ctx, iv_zero, ciphertext, ciphertext_len, plaintext_out);
Enter fullscreen mode Exit fullscreen mode

The key is baked straight into the binary. A few quirks make reproducing the exact wire format tricky:

  • The IV is fixed at all zero bytes (16 null bytes).
  • Plaintext is padded to the 16-byte AES block size with null bytes, not PKCS#7.
  • The trickiest part: capturing the actual bytes Foxit writes to disk in API Monitor shows a 00 byte interleaved with every other byte — meaning the plaintext is encoded as UTF-16LE before encryption. Encoding as plain ANSI/UTF-8 produces ciphertext the service will never accept.
  • The final ciphertext is hex-encoded, and that hex string is itself re-encoded as UTF-16 before being written to FoxitData.txt.

The full pipeline looks like this:

plaintext command string (key=value||key=value...)
   → UTF-16LE encode
   → pad with 0x00 to a multiple of 16 bytes
   → AES-128-CBC encrypt (key: "c6c7702dbcbf4678", IV: 0x00 * 16)
   → hex-encode ciphertext
   → UTF-16 encode the hex string
   → write to FoxitData.txt
Enter fullscreen mode Exit fullscreen mode

3. Service-Side Processing Flow

Reversing FoxitPDFReaderUpdateService.exe shows roughly this sequence after it reads FoxitData.txt:

  1. Extract sessionid from the decrypted command.
  2. Walk the process list to find the winlogon.exe belonging to that session.
  3. Open that process and duplicate its token (DuplicateTokenEx).
  4. Build an environment block from that token with bInheritHandles = TRUE, apparently to reconstruct the target session's desktop/environment context.
  5. Launch the executable named in strTempUpdaterPath in the SYSTEM security context via the CreateProcess family, passing csCommandLine verbatim.

Right before launch, two checks run:

  • A filename check confirming the target matches an expected name (e.g. FoxitPDFReaderUpdater.exe)
  • A certificate check confirming the binary carries a valid Foxit code-signing signature

So pointing strTempUpdaterPath at cmd.exe or an arbitrary binary fails the signature check. But if the attacker simply supplies the real, legitimately signed Foxit updater binary, that check becomes meaningless — it only verifies "did Foxit build this file," not "is everything this file loads also safe." That gap is exactly where the sideload comes in.

4. DLL/DRV Sideloading in a Privileged Context

Watching FoxitPDFReaderUpdater.exe in Procmon shows a burst of CreateFile calls against several DLLs in the current working directory (the attacker-controlled %APPDATA%\...\Foxit PDF Reader\ folder), most returning PATH NOT FOUND. Most of these carry anti-sideload checks — except one:

  • winspool.drv — referenced before every other library, and despite the .drv extension it's a regular PE that runs DllMain on load like any DLL.
  • oleaccrc.dll, by contrast, is a resource-only DLL loaded with LOAD_LIBRARY_AS_DATAFILE, so it can't execute code even if sideloaded.

Drop a malicious winspool.drv in the attacker-writable path, and FoxitPDFReaderUpdater.exe — now running as SYSTEM courtesy of the forged IPC command — loads it directly, completing arbitrary code execution as SYSTEM.

Interestingly, Foxit happened to close this exact entry point days after it was found, as part of an unrelated patch for two other bugs (CVE-2026-3775/CVE-2026-3780). But the same DLL-search-order flaw resurfaced through a second trigger: clicking a hyperlink inside the updater's "check for update" dialog reopened the identical sideload primitive. The entry point moved; the root cause — a signed SYSTEM process resolving DLLs from a user-writable directory first — did not.

5. Full Attack Chain

[low-privileged user process]
      │  ① Drop malicious winspool.drv in %APPDATA%\...\Foxit PDF Reader\
      │  ② Assemble IPC command (session id, updater path, arguments)
      │  ③ UTF-16LE encode → 0x00 pad → AES-128-CBC encrypt (hardcoded key, null IV)
      │  ④ Ciphertext → hex → UTF-16, written to FoxitData.txt
      ▼
[C:\ProgramData\Foxit Software\Foxit PDF Reader\FoxitData.txt]  (writable by Users)
      │  ⑤ FoxitPDFReaderUpdateService.exe (SYSTEM) detects the file change
      ▼
[FoxitPDFReaderUpdateService.exe : NT AUTHORITY\SYSTEM]
      │  ⑥ Decrypt with hardcoded key, match sessionid to winlogon.exe, duplicate token
      │  ⑦ Filename + signature checks pass (it's a genuine Foxit binary)
      │  ⑧ CreateProcess: launches %APPDATA%\...\FoxitPDFReaderUpdater.exe as SYSTEM
      ▼
[FoxitPDFReaderUpdater.exe : NT AUTHORITY\SYSTEM]
      │  ⑨ Resolves winspool.drv from its own directory per DLL search order
      ▼
[Attacker's winspool.drv DllMain executes] → arbitrary code execution as SYSTEM
Enter fullscreen mode Exit fullscreen mode

Here's the same flow as a diagram:

And the AES-128-CBC message construction on its own:

6. Root Causes

Three separate design mistakes had to overlap for this to work:

  • Broken trust boundary: a SYSTEM service treated a file writable by the Users group as trusted IPC input. Filesystem ACLs should have defined the trust boundary here, and they didn't.
  • Encryption mistaken for authentication: AES-128-CBC provides confidentiality, not integrity or authenticity — and since the key ships inside every client install, it was never actually secret to begin with. What this channel needed was a signature or HMAC the service alone could verify, not encryption.
  • Misplaced scope of code-signing checks: verifying that the launched executable itself is Authenticode-signed says nothing about every module that executable subsequently loads. Without controlling DLL search order, even a signed binary can become a privileged code-execution primitive.

7. Patch

Foxit shipped a coordinated fix on July 8, 2026 covering 30+ vulnerabilities across Reader and Editor for Windows and macOS. CVE-2026-57239 is fixed in the 2026.1.2 build (2026.x line), plus 14.0.5 and 13.2.5 for the supported 14.x/13.2 branches. Update via Help > Check for Update, or download a fresh installer from Foxit's official distribution channel and verify the reported version afterward.

Top comments (0)