diff --git a/src/Twig/Extension/UtilsExtension.php b/src/Twig/Extension/UtilsExtension.php index d02bbab..606d37d 100644 --- a/src/Twig/Extension/UtilsExtension.php +++ b/src/Twig/Extension/UtilsExtension.php @@ -20,6 +20,7 @@ use Twig\Extension\AbstractExtension; use Twig\TwigFilter; +use function Cake\Core\deprecationWarning; /** * Class UtilsExtension. @@ -34,8 +35,16 @@ class UtilsExtension extends AbstractExtension public function getFilters(): array { return [ - new TwigFilter('serialize', 'serialize'), - new TwigFilter('unserialize', 'unserialize'), + new TwigFilter('serialize', function (string $value): mixed { + deprecationWarning('5.0.2', 'Usage of serialize in templates deprecated.'); + + return serialize($value); + }), + new TwigFilter('unserialize', function (string $value): mixed { + deprecationWarning('5.0.2', 'unserialize is deprecated. Its usage creates arbitrary object deserialization issues'); + + return unserialize($value, ['allowed_classes' => false]); + }), new TwigFilter('md5', 'md5'), new TwigFilter('base64_encode', 'base64_encode'), new TwigFilter('base64_decode', 'base64_decode'), diff --git a/tests/TestCase/Twig/Extension/UtilsExtensionTest.php b/tests/TestCase/Twig/Extension/UtilsExtensionTest.php new file mode 100644 index 0000000..f9c1784 --- /dev/null +++ b/tests/TestCase/Twig/Extension/UtilsExtensionTest.php @@ -0,0 +1,55 @@ +extension = new UtilsExtension(); + } + + public function testUnserializePreventObject(): void + { + $this->skipIf(PHP_VERSION_ID < 80300, 'Requires PHP8.3 or higher'); + + $twig = new Environment(new ArrayLoader([ + // {% set %} so we exercise the filter without stringifying the result. + 'object' => '{% set _ = payload|unserialize %}(rendered)', + 'array' => '{{ (payload|unserialize)["role"] }}', + ])); + $twig->addExtension(new UtilsExtension()); + + // 1) Object payload: does a gadget's magic method run? + GadgetMarker::$woken = false; + $this->deprecated(function () use ($twig): void { + $twig->render('object', ['payload' => serialize(new GadgetMarker())]); + $this->assertFalse(GadgetMarker::$woken, 'Should not have modified GadgetMarker'); + + $out = $twig->render('array', ['payload' => serialize(['role' => 'editor'])]); + $this->assertStringContainsString('editor', $out); + }); + } +} diff --git a/tests/test_app/src/GadgetMarker.php b/tests/test_app/src/GadgetMarker.php new file mode 100644 index 0000000..a159879 --- /dev/null +++ b/tests/test_app/src/GadgetMarker.php @@ -0,0 +1,15 @@ +