Valinor is a PHP library that helps to map any input into a strongly-typed value object structure. Prior to version 0.12.0, Valinor can use…
GitHub_M·CWE-209·Published 2022-07-11
Valinor is a PHP library that helps to map any input into a strongly-typed value object structure. Prior to version 0.12.0, Valinor can use `Throwable#getMessage()` when it should not have permission to do so. This is a problem with cases such as an SQL exception showing an SQL snippet, a database connection exception showing database IP address/username/password, or a timeout detail / out of memory detail. Attackers could use this information for potential data exfiltration, denial of service attacks, enumeration attacks, etc. Version 0.12.0 contains a patch for this vulnerability.
Valinor is a PHP library that helps to map any input into a strongly-typed value object structure. Prior to version 0.12.0, Valinor can use `Throwable#getMessage()` when it should not have permission to do so. This is a problem with cases such as an SQL exception showing an SQL snippet, a database connection exception showing database IP address/username/password, or a timeout detail / out of memory detail. Attackers could use this information for potential data exfiltration, denial of service attacks, enumeration attacks, etc. Version 0.12.0 contains a patch for this vulnerability.
```php <?php namespace My\App; use CuyZ\Valinor\Mapper\MappingError; use CuyZ\Valinor\Mapper\Tree\Node; use CuyZ\Valinor\Mapper\Tree\NodeTraverser; use CuyZ\Valinor\MapperBuilder; require_once __DIR__ . '/Valinor/vendor/autoload.php'; final class Money { private function __construct(public readonly string $amount) { } public static function fromString(string $money): self { if (1 !== \preg_match('/^\d+ [A-Z]{3}$/', $money)) { throw new \InvalidArgumentException(\sprintf('Given "%s" is not a recognized monetary amount', $money)); } return new self($money); } } class Foo { public function __construct( private readonly Money $a, private readonly Money $b, private readonly Money $c, ) {} } $mapper = (new MapperBuilder()) ->registerConstructor([Money::class, 'fromString']) ->mapper(); try { var_dump($mapper->map(Foo::class, [ 'a' => 'HAHA', 'b' => '100 EUR', 'c' => 'USD 100' ])); } catch (MappingError $e) { $messages = (new NodeTraverser(function (Node $node) { foreach ($node->messages() as $message) { var_dump([ '$message', $message->path(), $message->body() ]); } return ''; }))->traverse($e->node()); iterator_to_array($messages); } ``` Now, this is quite innocent: it produces following output: ``` ❯ php value-object-conversion.php array(3) { [0]=> string(8) "$message" [1]=> string(1) "a" [2]=> string(48) "Given "HAHA" is not a recognized monetary amount" } array(3) { [0]=> string(8) "$message" [1]=> string(1) "c" [2]=> string(51) "Given "USD 100" is not a recognized monetary amount" } ``` The problem is that nowhere I told valinor that it could use `Throwable#getMessage()`. This is a problem with cases where you get: * an SQL exception showing an SQL snippet * a DB connection exception showing DB ip address/username/password * a timeout detail / out of memory detail (exploring DDoS possibilities) This allows for potential data exfiltration, DDoS, enumeration attacks, etc.
```php <?php namespace My\App; use CuyZ\Valinor\Mapper\MappingError; use CuyZ\Valinor\Mapper\Tree\Node; use CuyZ\Valinor\Mapper\Tree\NodeTraverser; use CuyZ\Valinor\MapperBuilder; require_once __DIR__ . '/Valinor/vendor/autoload.php'; final class Money { private function __construct(public readonly string $amount) { } public static function fromString(string $money): self { if (1 !== \preg_match('/^\d+ [A-Z]{3}$/', $money)) { throw new \InvalidArgumentException(\sprintf('Given "%s" is not a recognized monetary amount', $money)); } return new self($money); } } class Foo { public function __construct( private readonly Money $a, private readonly Money $b, private readonly Money $c, ) {} } $mapper = (new MapperBuilder()) ->registerConstructor([Money::class, 'fromString']) ->mapper(); try { var_dump($mapper->map(Foo::class, [ 'a' => 'HAHA', 'b' => '100 EUR', 'c' => 'USD 100' ])); } catch (MappingError $e) { $messages = (new NodeTraverser(function (Node $node) { foreach ($node->messages() as $message) { var_dump([ '$message', $message->path(), $message->body() ]); } return ''; }))->traverse($e->node()); iterator_to_array($messages); } ``` Now, this is quite innocent: it produces following output: ``` ❯ php value-object-conversion.php array(3) { [0]=> string(8) "$message" [1]=> string(1) "a" [2]=> string(48) "Given "HAHA" is not a recognized monetary amount" } array(3) { [0]=> string(8) "$message" [1]=> string(1) "c" [2]=> string(51) "Given "USD 100" is not a recognized monetary amount" } ``` The problem is that nowhere I told valinor that it could use `Throwable#getMessage()`. This is a problem with cases where you get: * an SQL exception showing an SQL snippet * a DB connection exception showing DB ip address/username/password * a timeout detail / out of memory detail (exploring DDoS possibilities) This allows for potential data exfiltration, DDoS, enumeration attacks, etc.
Valinor es una biblioteca de PHP que ayuda a mapear cualquier entrada en una estructura de objetos de valor fuertemente tipados. En versiones anteriores a 0.12.0, Valinor puede usar "Throwable#getMessage()" cuando no debería tener permiso para hacerlo. Esto es un problema en casos como una excepción SQL que muestra un fragmento de SQL, una excepción de conexión a la base de datos que muestra la dirección IP/nombre de usuario/contraseña de la base de datos, o un detalle de tiempo de espera / detalle de memoria agotada. Los atacantes podrían usar esta información para una potencial exfiltración de datos, ataques de denegación de servicio, ataques de enumeración, etc. La versión 0.12.0 contiene un parche para esta vulnerabilidad
| Version | Type | Source | Base | Exp | Impact | Vector |
|---|---|---|---|---|---|---|
| 2.0 | Primary | NVD | 6.4 | 10.0 | 4.9 | AV:N/AC:L/Au:N/C:P/I:N/A:P |
| 3.1 | Primary | NVD | 9.1 | 3.9 | 5.2 | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:H |
| 3.1 | Primary | cve.org | 7.5 | — | — | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N |
| 3.1 | Primary | cve.org | 7.5 | — | — | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N |
| 3.1 | Secondary | NVD | 7.5 | 3.9 | 3.6 | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N |
| 3.1 | Secondary | GHSA | 7.5 | — | — | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N |