Back to advisories
CVE-2026-45016 GHSA-c8m7-r2jv-rw63 Medium CVSS 6.5

Local File Inclusion via file:// URI in Mail Compose

Mail composition handler processes image URLs found in outgoing HTML email bodies without validating their URI scheme

Affected: egroupware < 26.7.20260702 Vendor: EGroupware Discovered: Reported: May 6, 2026 Patched: Jul 6, 2026 Reporter: Stefan Mitocaru
CVSS Vector: CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N

Details

EGroupware's mail composition handler processes image URLs found in outgoing HTML email bodies without validating their URI scheme. The condition used to detect local files checks only that the URL does not start with http, which evaluates to true for file:// URIs. This causes file_get_contents() to read arbitrary files from the server filesystem and embed their contents as inline MIME attachments in outgoing mail. Any authenticated user with mail access can exploit this to exfiltrate sensitive server files.


Details

Summary

Field Value
CVE ID CVE-2026-45016
GHSA GHSA-c8m7-r2jv-rw63
Severity High
CWE CWE-73 (External Control of File Name or Path)
Package egroupware (PHP)
Affected < 26.5.20260507
Vulnerability Arbitrary File Read via file:// URI in Inline Image Processing
Impact Server-side file disclosure to authenticated users

EGroupware's processURL2InlineImages function, located in api/src/Mail.php, iterates over image URLs embedded in an outgoing HTML email body and fetches their contents to embed them as inline MIME parts. The intent is to resolve relative or local HTTP URLs, but the URI scheme check is insufficient: it only rejects strings that start with http, allowing file://, ftp://, php://, and other schemes to pass through unchecked and reach file_get_contents().


How it works

The vulnerable logic sits inside the processURL2InlineImages function in api/src/Mail.php. For each image URL found in the HTML body, the code determines whether to fetch the file locally:

// api/src/Mail.php
foreach ($images[2] as $i => $url)
{
    $basedir = $data = '';
    $needTempFile = true;
    $attachmentData = ['name' => '', 'type' => '', 'file' => '', 'tmp_name' => ''];

    if (!str_starts_with($url, 'data:'))
    {
        $attachmentData['name'] = basename($url);
        if (($directory = dirname($url)) == '.') $directory = '';
        $ext = pathinfo($attachmentData['name'], PATHINFO_EXTENSION);
        $attachmentData['type'] = MimeMagic::ext2mime($ext);
        if (strlen($directory) > 1 && !str_ends_with($directory, '/')) {
            $directory .= '/';
        }
        // ...

        // Sink: file_get_contents is called when the URL does not start with "http"
        if ($myUrl[0] != '/' && strlen($basedir) > 1 && !str_ends_with($basedir, '/')) {
            $basedir .= '/';
        }
        if ($needTempFile && empty($attachment) && !str_starts_with($myUrl, "http"))
        {
            try {
                $data = file_get_contents($basedir . urldecode($myUrl)); // sink
            }
            catch (\Throwable $e) {
                _egw_log_exception($e);
            }
        }
    }
}

The condition !str_starts_with($myUrl, "http") is intended to identify local paths, but it also matches any URI scheme that is not HTTP or HTTPS. The evaluation for a file:// URI is unambiguous:

str_starts_with('file:///etc/passwd', 'http') → false
!false → true
→ file_get_contents('file:///etc/passwd') executes

The contents of the file are then written to a temporary file and attached to the outgoing email as an inline MIME part, where the sender can retrieve it from the sent message or a draft.


Root Cause

The scheme check relies on a negative string prefix match against a single value ("http") rather than an explicit allowlist of permitted schemes. This is a classic incomplete blocklist: it correctly excludes HTTP and HTTPS but permits every other scheme, including file://, ftp://, php://filter/, data://, and any future scheme that does not begin with the string http. The function was designed for convenience, resolving relative image paths in outgoing mail, but the absence of scheme validation turns it into an arbitrary file read primitive for any authenticated user.


Prerequisites

  • A valid EGroupware account with mail access (compose permission).
  • No elevated privileges are required.
  • The attacker sends the email to themselves or saves a draft; the file contents appear as an inline attachment in the message they retrieve.

Fix

Replace the incomplete prefix check with a strict scheme allowlist using a regular expression that explicitly permits only http:// and https:// and rejects everything else:

// Before (vulnerable): rejects only strings starting with "http"
if ($needTempFile && empty($attachment) && !str_starts_with($myUrl, "http"))
{
    $data = file_get_contents($basedir . urldecode($myUrl));
}

// After (safe): allowlist of permitted schemes, all others are skipped
if (!preg_match('#^https?://#i', $myUrl))
{
    continue; // reject file://, ftp://, php://, data://, and anything else
}

if ($needTempFile && empty($attachment))
{
    $data = file_get_contents($basedir . urldecode($myUrl));
}

This ensures that file://, ftp://, php://filter/, and any other non-HTTP scheme never reach file_get_contents(), regardless of how the URL is constructed or encoded.


Key Takeaways

  • Negative prefix checks are not URI scheme validation. Checking that a string does not start with "http" is not equivalent to checking that it is a relative path; it permits every non-HTTP scheme that exists or will ever exist.
  • File fetch functions must only operate on explicitly allowed schemes. Any call to file_get_contents(), fopen(), curl_exec(), or similar functions that processes user-supplied URLs needs a strict scheme allowlist upstream, not a blocklist.
  • Low-privilege accounts are sufficient for exploitation. Because the vulnerable feature is part of the standard mail compose workflow, no administrative access is required. Any user with a mailbox can trigger the file read.
  • The impact extends beyond /etc/passwd. Configuration files containing database credentials, private keys, environment files, and application secrets are equally readable if the web server process has read access to them.

Proof of Concept

Proof of Concept Sanitized for safety
Note: This proof of concept is published for educational and defensive purposes after coordinated disclosure. Do not use it against systems you do not own or have explicit permission to test.

Open the mail compose window and switch to HTML body mode. Insert the following image tag referencing a sensitive server file:

<img src="file:///etc/passwd">

Any file readable by the web server process can be targeted. High-value targets include:

file:///etc/passwd
file:///var/www/html/egroupware/api/config.php
file:///proc/self/environ

Send the message to any address, including the attacker's own account, or save it as a draft. The processURL2InlineImages function runs during MIME assembly, before the message leaves the server.

Open the sent message or draft. The file referenced by the file:// URI has been fetched by the server, written to a temporary file, and attached as an inline MIME part. The contents of /etc/passwd (or whichever file was targeted) are now embedded in the message body and fully readable by the attacker.

Content-Type: text/plain; name="passwd"
Content-Transfer-Encoding: base64
Content-Disposition: inline; filename="passwd"

cm9vdDp4OjA6MDpyb290Oi9yb290Oi9iaW4vYmFzaAo...

Start securing your codebase today

Connect your repositories and let AI agents handle continuous scanning, research, and triage.

Have questions? Get in touch →