CVE-2026-39932 Overview
CVE-2026-39932 is a remote code execution vulnerability in OpenEMR through version 8.2.0. The flaw resides in the document category tree component library/classes/Tree.class.php, which passes attacker-controlled data from the categories database table into an unsanitized eval() call. An authenticated administrator can chain arbitrary SQL execution to alter the id column type to VARCHAR and insert a malicious PHP payload. The payload executes whenever any page instantiates CategoryTree, including unauthenticated and low-privilege pages, yielding command execution as the web server user [CWE-95].
Critical Impact
A single administrator-planted payload converts every page that loads the category tree, including anonymous entry points, into a code execution primitive running as the web server user.
Affected Products
- OpenEMR versions through 8.2.0
- The library/classes/Tree.class.phpCategoryTree component
- OpenEMR deployments exposing document category functionality to unauthenticated users
Discovery Timeline
- 2026-08-03 - CVE-2026-39932 published to NVD
- 2026-08-03 - Last updated in NVD database
Technical Details for CVE-2026-39932
Vulnerability Analysis
OpenEMR builds its document category hierarchy through the CategoryTree class defined in library/classes/Tree.class.php. The class reads records from the categories table and feeds fields into a PHP eval() construct to build the runtime tree structure. The code assumes numeric identifiers and does not sanitize or type-check the values before evaluation.
Exploitation requires two chained steps by an authenticated administrator with SQL execution capability. First, the attacker alters the id column in the categories table to VARCHAR, expanding it beyond its expected integer type. Second, the attacker inserts a row containing a PHP payload in place of the numeric identifier. The payload persists in the database and executes each subsequent time any request instantiates CategoryTree.
Because CategoryTree is referenced from unauthenticated and low-privilege pages, the initial administrator action bootstraps persistent RCE reachable by anonymous requests. Command execution runs under the web server process identity, granting access to patient records, configuration files, and outbound network paths.
Root Cause
The root cause is use of eval() on data that originates in the database without input validation or output escaping [CWE-95: Improper Neutralization of Directives in Dynamically Evaluated Code]. The design trusts that stored category identifiers are numeric, while the underlying schema can be redefined through the same administrative SQL interface.
Attack Vector
The attack vector is network-based and requires high privileges for initial compromise but no user interaction after the payload is planted. An attacker with administrator access uses the built-in SQL execution feature to modify the categories schema and insert a crafted string. Subsequent HTTP requests, including those from unauthenticated visitors, trigger evaluation of the string and execute arbitrary operating system commands as the web server user.
For technical walkthroughs, see the Jiva Security CVE-2026-39932 Writeup and the VulnCheck OpenEMR RCE Advisory.
Detection Methods for CVE-2026-39932
Indicators of Compromise
- Non-numeric values in the id column of the OpenEMR categories table, particularly strings containing PHP tokens such as system(, passthru(, exec(, or backticks.
- Schema drift on the categories table where the id column type is VARCHAR instead of an integer type.
- Web server processes (apache, www-data, nginx, php-fpm) spawning shells (/bin/sh, bash) or reconnaissance binaries (id, whoami, curl, wget).
- Outbound network connections from the OpenEMR host to attacker infrastructure immediately following requests to pages that render document categories.
Detection Strategies
- Audit the categories table schema and content on every OpenEMR instance and alert on any non-integer id values.
- Enable and forward OpenEMR audit logs covering the SQL execution interface, then alert on ALTER TABLE categories and INSERT INTO categories statements originating from administrator accounts.
- Instrument PHP with disable_functions monitoring or an OPcache scanner to flag runtime eval() execution paths reached from Tree.class.php.
- Correlate anonymous HTTP requests to pages invoking CategoryTree with child process creation events on the web server host.
Monitoring Recommendations
- Ship web server, PHP, and OpenEMR application logs to a centralized analytics platform and retain them for at least 90 days.
- Monitor for unexpected outbound connections from the OpenEMR host, especially to newly registered domains or non-standard ports.
- Track administrator session activity, focusing on use of the SQL query tool and any DDL statements against clinical schema tables.
- Baseline the parent-child process tree of the PHP runtime and alert on any deviation involving shell interpreters or download utilities.
How to Mitigate CVE-2026-39932
Immediate Actions Required
- Restrict administrator access to the OpenEMR SQL execution interface and remove standing administrator rights from accounts that do not require them.
- Inspect the categories table on all instances, confirm the id column is an integer type, and remove any rows containing PHP syntax.
- Place OpenEMR behind an authenticated reverse proxy or VPN until a fixed release is deployed and validated.
- Rotate credentials, session secrets, and API keys stored on any host where a suspicious categories row has been observed.
Patch Information
No vendor patch reference is included in the NVD entry at the time of publication. Monitor the OpenEMR project releases and the referenced advisories from Jiva Security and VulnCheck for fixed version guidance. Until a patched build is available, treat any OpenEMR deployment through version 8.2.0 as vulnerable.
Workarounds
- Deploy a web application firewall rule that blocks requests to pages instantiating CategoryTree from unauthenticated sources.
- Enforce strict schema controls on the OpenEMR database by revoking ALTER privileges from the OpenEMR application account where operationally feasible.
- Apply a local hotfix that casts id values to integer before they reach eval() in library/classes/Tree.class.php, or replace the eval() construct with a data-driven tree builder.
- Segment the OpenEMR host from sensitive internal networks so that a compromised web server user cannot pivot to clinical data stores.
# Configuration example: verify categories table integrity
mysql -u openemr -p openemr -e "\
SELECT id, name FROM categories \
WHERE id REGEXP '[^0-9]' OR CHAR_LENGTH(id) > 10;"
# Confirm the id column is an integer type
mysql -u openemr -p openemr -e "\
SHOW COLUMNS FROM categories LIKE 'id';"
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

