Back to Intelligence

ZDI-26-615: Unpatched PDF Architect Privilege Escalation — Detection and Mitigation Guide

SA
Security Arsenal Team
September 1, 2026
13 min read

The Zero Day Initiative has published ZDI-26-615, a currently unpatched local privilege escalation vulnerability in pdfforge PDF Architect, a widely deployed PDF editing and conversion suite common in enterprise and legal/finance environments. The flaw is an Uncontrolled Search Path Element (CWE-427) in the product's activation-service / update service, and it carries a CVSS score of 7.8.

The exploitation precondition matters: an attacker must first be able to execute low-privileged code on the target host. In practice, that bar is trivially cleared — any phished user, any initial-access broker payload, or any commodity malware running as a standard user can leverage this bug to become NT AUTHORITY\SYSTEM. This is exactly the class of vulnerability that turns a contained intrusion into a full domain compromise. Since there is no vendor patch as of publication, detection and compensating controls are your only defense.


Technical Analysis

Affected Component

AttributeDetail
Productpdfforge PDF Architect
ComponentActivation service / Update Service (Windows service running with elevated privileges)
Vulnerability classUncontrolled Search Path Element (CWE-427) — DLL search order hijacking against a privileged service
AdvisoryZDI-26-615 (http://www.zerodayinitiative.com/advisories/ZDI-26-615/)
CVENone assigned at time of writing (ZDI 0day track — vendor exceeded disclosure window)
CVSS7.8 (High) — local, low complexity, no user interaction, scope unchanged
Patch statusUnpatched

How the Vulnerability Works

Uncontrolled search path vulnerabilities in privileged Windows services follow a well-worn pattern:

  1. The PDF Architect activation/update service runs as SYSTEM (or an otherwise elevated account).
  2. When the service starts — or when an update/activation workflow is triggered — it loads one or more DLLs using an insecure search order, resolving the module name against directories a low-privileged user can write to (for example, a world-writable application subdirectory, the service's working directory, or a user-controllable PATH element).
  3. A local attacker plants a malicious DLL with the expected name into the attacker-writable directory that sits earlier in the search order than the legitimate module location.
  4. On the next service start or activation/update cycle, the privileged service loads the attacker's DLL, executing arbitrary code in the SYSTEM context.

The activation/update service angle is notable for two reasons. First, update services are frequently auto-start, so exploitation is durable across reboots — this doubles as a persistence mechanism. Second, update frameworks routinely load plugin or helper libraries dynamically, which expands the number of candidate DLL names an attacker can squat on.

Exploitation Status

  • Patch: None. This is a ZDI 0day advisory, meaning the coordinated disclosure timeline expired without a vendor fix.
  • CVE: Not yet assigned. Track ZDI-26-615 for a CVE assignment.
  • Public PoC / in-the-wild exploitation: No confirmed public exploit or CISA KEV listing at publication time. However, DLL search-order hijacks are among the most reliably weaponized LPE primitives — expect proof-of-concept code to appear quickly now that the advisory is public. Treat this as exploitable in practice, not theoretical.

Why Defenders Should Care Even Before a PoC Drops

PDF Architect is frequently deployed via silent MSI installers across whole fleets — it is not a niche single-user tool. Any environment where standard users have PDF Architect installed has a SYSTEM-level escalation path sitting on every endpoint. If you cannot inventory it, assume you have it.


Detection & Response

The most reliable detection surface for CWE-427 exploitation is file creation of DLLs in application-adjacent writable paths by non-SYSTEM principals, followed by the elevated service process loading that DLL or spawning unexpected children. Below are detection packages targeting exactly that behavior chain.

Sigma Rules

YAML
---
title: DLL Planted in pdfforge PDF Architect Directory by Non-System Process
id: 3f8c2a91-6d4e-4b7a-9c21-5e7f0a8b1d33
status: experimental
description: Detects creation of DLL files in PDF Architect installation or service directories by processes other than trusted installers, consistent with DLL search-order hijacking against the activation/update service (ZDI-26-615).
references:
  - http://www.zerodayinitiative.com/advisories/ZDI-26-615/
  - https://attack.mitre.org/techniques/T1574/001/
author: Security Arsenal
date: 2026/01/15
tags:
  - attack.privilege_escalation
  - attack.persistence
  - attack.t1574.001
logsource:
  category: file_event
  product: windows
detection:
  selection_path:
    TargetFilename|contains:
      - '\pdfforge\'
      - '\PDF Architect\'
      - '\PDFArchitect\'
  selection_ext:
    TargetFilename|endswith: '.dll'
  filter_installers:
    Image|endswith:
      - '\msiexec.exe'
      - '\TrustedInstaller.exe'
      - '\PDF Architect\Setup.exe'
  filter_system:
    User|contains: 'SYSTEM'
  condition: selection_path and selection_ext and not 1 of filter_*
falsepositives:
  - Legitimate vendor updates deploying new modules (filter on signed updater processes once confirmed)
  - Software deployment tools (SCCM/Intune) — tune by Image
description_fp: Tune installer filters to your software deployment tooling after baseline.
level: high
---
title: PDF Architect Service Spawning Command Interpreter or Script Host
id: 9b1e4d72-3a58-4f6c-8d02-7c5e9a0b2f44
status: experimental
description: Detects the PDF Architect activation/update service or main process spawning cmd, PowerShell, rundll32, or other LOLBins — a strong post-exploitation signal after SYSTEM-level code execution via DLL hijack (ZDI-26-615).
references:
  - http://www.zerodayinitiative.com/advisories/ZDI-26-615/
  - https://attack.mitre.org/techniques/T1059/
author: Security Arsenal
date: 2026/01/15
tags:
  - attack.execution
  - attack.privilege_escalation
  - attack.t1059
logsource:
  category: process_creation
  product: windows
detection:
  selection_parent:
    ParentImage|contains:
      - '\pdfforge\'
      - '\PDF Architect\'
      - '\PDFArchitect\'
  selection_child:
    Image|endswith:
      - '\cmd.exe'
      - '\powershell.exe'
      - '\pwsh.exe'
      - '\wscript.exe'
      - '\cscript.exe'
      - '\mshta.exe'
      - '\rundll32.exe'
      - '\regsvr32.exe'
      - '\wmic.exe'
      - '\net.exe'
      - '\net1.exe'
  condition: selection_parent and selection_child
falsepositives:
  - Rare — vendor updaters occasionally invoke shells for post-install tasks; validate against signed vendor binaries and known update windows
level: critical
---
title: Service Executable Running from User-Writable Path Referencing PDF Architect
id: 5d2a7f18-8c43-4e19-b630-1f4a6c9d3e55
status: experimental
description: Detects service control manager launching binaries from user-profile or temp paths with PDF Architect-related names, indicating a hijacked or impersonated activation/update service.
references:
  - http://www.zerodayinitiative.com/advisories/ZDI-26-615/
  - https://attack.mitre.org/techniques/T1574/
author: Security Arsenal
date: 2026/01/15
tags:
  - attack.privilege_escalation
  - attack.persistence
  - attack.t1574
logsource:
  category: process_creation
  product: windows
detection:
  selection_path:
    Image|contains:
      - '\Users\'
      - '\AppData\'
      - '\Temp\'
      - '\ProgramData\'
  selection_name:
    Image|contains:
      - 'pdfarchitect'
      - 'activation'
      - 'pdfforge'
  condition: selection_path and selection_name
falsepositives:
  - User-context PDF Architect components legitimately installed per-user — verify install scope in your environment
level: high

A note on fidelity: the second rule (service spawning LOLBins) is the highest-signal rule here and should be deployed broadly if PDF Architect exists anywhere in the fleet. The first rule requires tuning to your software deployment tooling — expect a one-time baseline of installer noise, then near-silence.

KQL — Microsoft Sentinel / Defender for Endpoint

This hunt looks for the two halves of the kill chain: non-SYSTEM DLL drops into pdfforge paths, and the privileged service subsequently spawning suspicious children. Run it over 14 days to establish a baseline, then convert to an analytics rule.

KQL — Microsoft Sentinel / Defender
// ZDI-26-615 hunt: DLL planting + suspicious service children for PDF Architect
let pdfforgePaths = dynamic(["pdfforge", "PDF Architect", "PDFArchitect"]);
let suspiciousChildren = dynamic(["cmd.exe", "powershell.exe", "pwsh.exe", "wscript.exe", "cscript.exe", "mshta.exe", "rundll32.exe", "regsvr32.exe", "wmic.exe", "net.exe", "net1.exe"]);
let dllDrops =
  DeviceFileEvents
  | where TimeGenerated > ago(14d)
  | where FolderPath has_any (pdfforgePaths) and FileName endswith ".dll"
  | where InitiatingProcessFileName !in~ ("msiexec.exe", "trustedinstaller.exe")
  | where InitiatingProcessAccountName !~ "system"
  | project DropTime=TimeGenerated, DeviceName, FolderPath, FileName,
            DroppedBy=InitiatingProcessFileName, DropAccount=InitiatingProcessAccountName,
            SHA256, ReportId;
let serviceChildren =
  DeviceProcessEvents
  | where TimeGenerated > ago(14d)
  | where InitiatingProcessFolderPath has_any (pdfforgePaths)
  | where FileName in~ (suspiciousChildren)
  | project SpawnTime=TimeGenerated, DeviceName, ServiceProcess=InitiatingProcessFileName,
            ServiceAccount=InitiatingProcessAccountName, ChildProcess=FileName,
            ChildCommandLine=ProcessCommandLine, ReportId;
dllDrops
| join kind=fullouter serviceChildren on DeviceName
| order by DeviceName asc, DropTime asc

For environments ingesting Sysmon via SecurityEvent, this companion query catches the process-spawn side:

KQL — Microsoft Sentinel / Defender
SecurityEvent
| where EventID == 4688
| where TimeGenerated > ago(14d)
| where ParentProcessName has_any ("pdfforge", "PDF Architect", "PDFArchitect")
| where NewProcessName has_any ("cmd.exe", "powershell.exe", "rundll32.exe", "mshta.exe", "wmic.exe", "net.exe")
| project TimeGenerated, Computer, ParentProcessName, NewProcessName, CommandLine, AccountName
| order by TimeGenerated desc

Velociraptor VQL

Use this artifact to sweep the fleet for the two things that matter forensically: which machines have the vulnerable service installed, and whether any unsigned/unexpected DLLs are sitting in the application directories. This doubles as your exposure inventory while no patch exists.

VQL — Velociraptor
-- ZDI-26-615: Inventory PDF Architect service + hunt planted DLLs
LET service = SELECT Name, DisplayName, PathName, StartName, State
FROM wmi(query="SELECT Name, DisplayName, PathName, StartName, State FROM Win32_Service WHERE PathName LIKE '%PDF Architect%' OR PathName LIKE '%pdfforge%' OR DisplayName LIKE '%PDF Architect%'")

LET dlls = SELECT FullPath, Size, Mtime,
           Authenticode.Description AS Signature,
           Authenticode.Status AS SignatureStatus
FROM glob(globs=[
  'C:/Program Files/pdfforge/**/*.dll',
  'C:/Program Files (x86)/pdfforge/**/*.dll',
  'C:/Program Files/PDF Architect*/**/*.dll',
  'C:/Program Files (x86)/PDF Architect*/**/*.dll'
])
WHERE NOT SignatureStatus =~ 'OK'
   OR NOT Signature =~ 'pdfforge'

SELECT * FROM service
UNION ALL
SELECT FullPath AS Name, Signature AS DisplayName, FullPath AS PathName,
       SignatureStatus AS StartName, Mtime AS State
FROM dlls

In practice, split this into two artifacts — one for service inventory, one for unsigned DLL enumeration — so you can schedule the inventory daily and the DLL sweep hourly without the WMI join overhead.

Remediation & Verification Script

Until pdfforge ships a fix, the highest-value compensating control is locking down ACLs on the installation directory so standard users cannot write into any path the privileged service searches. This PowerShell script inventories the service, audits current permissions, reports write access held by non-administrative principals, and optionally hardens the ACLs. Run it read-only first (-AuditOnly), review, then enforce.

PowerShell
# ZDI-26-615 — PDF Architect uncontrolled search path mitigation
# Audit and harden ACLs on pdfforge PDF Architect install directories.
# Usage: run -AuditOnly first; then re-run with -Enforce to remediate.

[CmdletBinding()]
param(
    [switch]$AuditOnly,
    [switch]$Enforce
)

$report = @()

# 1. Locate PDF Architect services and install paths
$services = Get-CimInstance Win32_Service | Where-Object {
    $_.PathName -match 'pdfforge|PDF Architect' -or $_.DisplayName -match 'PDF Architect'
}

if (-not $services) {
    Write-Host "[+] No PDF Architect services found on this host." -ForegroundColor Green
    exit 0
}

foreach ($svc in $services) {
    $report += [PSCustomObject]@{
        Type        = 'Service'
        Name        = $svc.Name
        DisplayName = $svc.DisplayName
        RunAs       = $svc.StartName
        State       = $svc.State
        BinaryPath  = $svc.PathName
        Issue       = if ($svc.StartName -match 'LocalSystem|SYSTEM') { 'Runs as SYSTEM — high-impact LPE target' } else { 'Review run-as account' }
    }
    Write-Host "[!] Service: $($svc.Name) | Runs as: $($svc.StartName) | $($svc.State)" -ForegroundColor Yellow
}

# 2. Enumerate install directories
$installRoots = @(
    "$env:ProgramFiles\pdfforge",
    "${env:ProgramFiles(x86)}\pdfforge"
) + (Get-ChildItem "$env:ProgramFiles","${env:ProgramFiles(x86)}" -Directory -Filter 'PDF Architect*' -ErrorAction SilentlyContinue).FullName

foreach ($root in ($installRoots | Where-Object { $_ -and (Test-Path $_) })) {
    $acl = Get-Acl $root
    $writable = $acl.Access | Where-Object {
        $_.FileSystemRights -match 'Write|Modify|FullControl' -and
        $_.IdentityReference -notmatch 'SYSTEM|Administrators|TrustedInstaller' -and
        $_.AccessControlType -eq 'Allow'
    }

    foreach ($entry in $writable) {
        $report += [PSCustomObject]@{
            Type        = 'WeakACL'
            Name        = $root
            DisplayName = $entry.IdentityReference
            RunAs       = ''
            State       = ''
            BinaryPath  = $entry.FileSystemRights
            Issue       = 'Non-admin principal has write access — DLL plant possible'
        }
        Write-Host "[VULN] $($entry.IdentityReference) has $($entry.FileSystemRights) on $root" -ForegroundColor Red
    }

    # 3. Harden: strip non-admin write/modify ACEs (inheritance-preserved admin/system ACEs stay)
    if ($Enforce -and $writable) {
        foreach ($entry in $writable) {
            $acl.RemoveAccessRule($entry) | Out-Null
        }
        Set-Acl -Path $root -AclObject $acl
        Write-Host "[FIXED] Hardened ACLs on $root" -ForegroundColor Green
    }
}

# 4. Check for suspicious unsigned DLLs already present
$planted = foreach ($root in $installRoots) {
    if ($root -and (Test-Path $root)) {
        Get-ChildItem $root -Recurse -Filter *.dll -ErrorAction SilentlyContinue | Where-Object {
            (Get-AuthenticodeSignature $_.FullName).Status -ne 'Valid'
        }
    }
}
foreach ($dll in $planted) {
    $report += [PSCustomObject]@{
        Type='UnsignedDLL'; Name=$dll.FullName; DisplayName=''; RunAs=''; State='';
        BinaryPath=''; Issue='Unsigned DLL in install path — investigate immediately'
    }
    Write-Host "[ALERT] Unsigned DLL: $($dll.FullName)" -ForegroundColor Red
}

$report | Export-Csv -Path "$env:TEMP\ZDI-26-615-audit-$(Get-Date -Format yyyyMMdd-HHmm).csv" -NoTypeInformation
Write-Host "`nReport written to $env:TEMP. Re-run with -Enforce to apply ACL hardening." -ForegroundColor Cyan

Deploy this via your RMM/Intune/SCCM as a compliance baseline: audit mode fleet-wide today, enforce mode after you've validated no vendor updater breakage (test against a pilot ring — if the updater requires write access for self-updates, scope the ACL removal to DLL-adjacent subdirectories rather than the root).


Remediation

There is no patch. Until pdfforge releases a fixed build, prioritize in this order:

  1. Inventory and exposure reduction. Use the VQL artifact and PowerShell script above to enumerate every host with the PDF Architect activation/update service. If the product isn't business-critical on a given host, uninstall it — removal is the only complete fix right now.
  2. ACL hardening. Remove write/modify permissions for non-administrative principals on all pdfforge installation directories. This directly severs the DLL-planting prerequisite for the most common exploitation path.
  3. Application control. Enforce WDAC or AppLocker rules blocking unsigned DLL loads from pdfforge paths, or constrain the service's allowed module set. On Windows 10/11 Enterprise, DllSignature policy rules in WDAC are effective against search-order hijacks.
  4. Disable the service where feasible. If activation/update functionality is not required between maintenance windows, set the service to Disabled and re-enable it only under controlled patching conditions. A service that isn't running can't load a planted DLL.
  5. Deploy the detections. The critical-level Sigma rule (service spawning LOLBins) should go live immediately on any host that retains PDF Architect. Configure alerting to page on that rule — a PDF utility spawning cmd.exe as SYSTEM is never benign on first sight.
  6. Monitor for the vendor fix. Track the ZDI advisory page and pdfforge's release channels. When a patch ships, expect a CVE assignment; map it into your vulnerability management workflow immediately and apply within your critical LPE SLA (recommend ≤72 hours) given the weaponization velocity of this bug class.
  7. Watch CISA KEV. If exploitation is confirmed in the wild, this will land in the KEV catalog with a federal remediation deadline — a useful forcing function for internal prioritization even outside FCEB scope.

Escalation Guidance for IR

If any detection fires: treat the host as potentially SYSTEM-compromised. Capture the planted DLL (hash, signature, compile timestamp), enumerate service start events around the file creation time, and pivot on whatever the service spawned afterward — SYSTEM access from a local foothold is typically followed within minutes by credential theft (LSASS access) and lateral movement staging.


The Bigger Lesson

ZDI-26-615 is a 2026 advisory for a vulnerability class that has been understood for over two decades. Uncontrolled search path elements in privileged services remain one of the most productive LPE surfaces on Windows precisely because third-party updater and licensing services are everywhere, rarely audited, and almost always run as SYSTEM. Two durable takeaways:

  • Your attack surface includes every vendor updater on the fleet, not just the OS. Software inventory that doesn't enumerate services and their ACLs is blind to this entire class.
  • ZDI 0day-track advisories are your early warning system. The disclosure-before-patch model exists to pressure vendors, but it hands defenders a head start — use the window to harden and instrument before exploit code circulates.

Related Resources

Security Arsenal Penetration Testing Services AlertMonitor Platform Book a SOC Assessment vulnerability-management Intel Hub

Is your security operations ready?

Get a free SOC assessment or see how AlertMonitor cuts through alert noise with automated triage.