CVE(s):

CVE-2025-67076

CVE-2025-67077

CVE-2025-67078

CVE-2025-67079

Product:

Agora Project

Severity:

High

Affected version(s):

≤ v25.6.4

Fixed version(s):

v25.10

Introduction

Agora Project is an open-source collaboration platform designed to facilitate shared file storage, notes, task management, calendars, and other collaborative features for teams and organizations.

Issue

Multiple security vulnerabilities were identified in the Agora Project affecting version 25.6.4. These issues allow unauthenticated file disclosure and, once authenticated (or operating in guest mode if enabled), arbitrary code execution through unsafe file handling mechanisms. In addition, a cross-site scripting (XSS) vulnerability was identified in the error handling logic.

Taken together, these vulnerabilities may allow attackers to read sensitive files, upload and execute malicious payloads, and execute arbitrary JavaScript in users’ browsers.

Timeline

Date Description
19/08/2025 Reporting vulnerabilities
20/08/2025 Response from the publisher
02/10/2025 A fix has been released
06/01/2026 CVE identifiers have been reserved

Technical details

Unauthenticated File Read / CVE-2025-67076

Under certain conditions, it is possible for an unauthenticated attacker to read files from the system through the misc controller and the ExternalGetFile action.


/********************************************************************************************************
     * FICHIER JOINT : DOWNLOAD D'UN FICHIER ("nameMd5" : cf. "actionExternalGetFile()")
     ********************************************************************************************************/
    public static function actionAttachedFileDownload()
    {
        $curFile=MdlObject::attachedFileInfos(Req::param("_id"));
        $isFile = is_file($curFile["path"]);
        $md1 = md5($curFile["name"]);
        $md2 = Req::param("nameMd5");
        if(is_file($curFile["path"])  &&  ($curFile["containerObj"]->readRight() || md5($curFile["name"])==Req::param("nameMd5")))
            {File::download($curFile["name"],$curFile["path"]);}
    }

  public static function attachedFileInfos($file)
    {
        if(!empty($file)){
            if(is_numeric($file))  {$file=Db::getLine("SELECT * FROM ap_objectAttachedFile WHERE _id=".(int)$file);}            //Si besoin, récupère les infos en bdd
            $file["path"]=PATH_OBJECT_ATTACHMENT.$file["_id"].".".File::extension($file["name"]);                               //Path/chemin réel du fichier
            [...]
            return $file;
        }
    }

Note that the _id GET parameter can be an array containing arbitrary data. As a result, the MD5 check becomes meaningless, since we control both values being compared.

The path of the downloaded file is also built from data we control within this array; the only remaining constraint is the appended dot, which prevents reading files that do not have an extension.

The final payload looks like this:

/index.php?ctrl=misc&launchDownload=true&typeId=file-&action=ExternalGetFile&nameMd5=<@md5>test<@md5>&_id[name]=test&_id[_id]=../config.inc&_id[objectType]=file&_id[_idObject]=1

This issue allows access to files that have an extension, which may include configuration files, exported data, or other sensitive resources depending on the server configuration and file placement.

Insufficient blacklisting of dangerous file types / CVE-2025-67077

This vulnerability can be exploited while authenticated or as a guest if the option is enabled. File type and extension verification is not restrictive enough.


public static function uploadControl($tmpFile, $tmpDatasFolderSize=null)  
{
    if($tmpFile["error"]==0 && is_file($tmpFile["tmp_name"])){
      [...]
      $isForbiddenMimeType=preg_match("/(php|javascript|shell|binary|executable|msdownload|debian)/i", finfo_file($finfo,$tmpFile["tmp_name"]));

      if(self::isType("forbiddenExt",$tmpFile["name"]) || $isForbiddenMimeType==true) {     
        Ctrl::notify(Txt::trad("NOTIF_fileVersionForbidden")." : ".$tmpFile["name"]);  
        return false;
      }
      elseif(is_uploaded_file($tmpFile["tmp_name"])==false && Req::param("tmpFolderName")==false)   {
        Ctrl::notify("NOTIF_fileOrFolderAccess");  
        return false;
      }
      else  {
        return true;
      }
    }
  }

The extension check is based solely on a blacklist, it is possible to upload a ".phar" file that will be executed according to the web server configuration. Using the file controller and the UploadTmpFile action, it is possible to choose the directory where the file will be uploaded and thus go back to the webroot.

This gives us command execution and server compromise.

Code execution via file upload and Imagick / CVE-2025-67079

The Imagick library supports the MSL (Magick Scripting Language), which allows files to be read and written. It is possible to upload a fake PDF, and the thumbnail feature will use Imagick to read the PDF, which will then be interpreted as MSL and lead to the execution of PHP code.

To prevent ImageMagick from interpreting MSL (Magick Scripting Language), you must explicitly disable it in the policy.xml configuration file. This can be done by adding a policy rule that denies all rights to the MSL coder.

For example, inserting <policy domain="coder" rights="none" pattern="MSL"/> inside the <policymap> section ensures that any attempt to load or execute MSL files will be blocked at the ImageMagick level. This is the recommended and most reliable way to mitigate MSL-related security risks.

Cross-Site Scripting (XSS) / CVE-2025-67078

The notify parameter of the file controller used to display errors is not properly escaped, making it possible to inject JavaScript into the browser of a tricked user.

Resources