Skip to content

Commit 2eb3308

Browse files
committed
Disallow non closures in sort filter when the sanbox mode is enabled
1 parent e056e63 commit 2eb3308

File tree

3 files changed

+18
-15
lines changed

3 files changed

+18
-15
lines changed

CHANGELOG

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
# 2.14.11 (2022-XX-XX)
1+
# 2.14.11 (2022-02-04)
22

3-
* n/a
3+
* Fix a security issue when in a sandbox: the `sort` filter must require a Closure for the `arrow` parameter
44

55
# 2.14.10 (2022-01-03)
66

7-
* Allow more null arguments when Twig expects a string (for better 8.1 support)
7+
* Allow more null arguments when Twig expects a string (for better 8.1 support)
88

99
# 2.14.9 (2022-01-03)
1010

src/Extension/CoreExtension.php

+14-11
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ public function getFilters()
237237
// array helpers
238238
new TwigFilter('join', 'twig_join_filter'),
239239
new TwigFilter('split', 'twig_split_filter', ['needs_environment' => true]),
240-
new TwigFilter('sort', 'twig_sort_filter'),
240+
new TwigFilter('sort', 'twig_sort_filter', ['needs_environment' => true]),
241241
new TwigFilter('merge', 'twig_array_merge'),
242242
new TwigFilter('batch', 'twig_array_batch'),
243243
new TwigFilter('column', 'twig_array_column'),
@@ -926,7 +926,7 @@ function twig_reverse_filter(Environment $env, $item, $preserveKeys = false)
926926
*
927927
* @return array
928928
*/
929-
function twig_sort_filter($array, $arrow = null)
929+
function twig_sort_filter(Environment $env, $array, $arrow = null)
930930
{
931931
if ($array instanceof \Traversable) {
932932
$array = iterator_to_array($array);
@@ -935,6 +935,8 @@ function twig_sort_filter($array, $arrow = null)
935935
}
936936

937937
if (null !== $arrow) {
938+
twig_check_arrow_in_sandbox($env, $arrow, 'sort', 'filter');
939+
938940
uasort($array, $arrow);
939941
} else {
940942
asort($array);
@@ -1606,9 +1608,7 @@ function twig_array_filter(Environment $env, $array, $arrow)
16061608
throw new RuntimeError(sprintf('The "filter" filter expects an array or "Traversable", got "%s".', \is_object($array) ? \get_class($array) : \gettype($array)));
16071609
}
16081610

1609-
if (!$arrow instanceof Closure && $env->hasExtension('\Twig\Extension\SandboxExtension') && $env->getExtension('\Twig\Extension\SandboxExtension')->isSandboxed()) {
1610-
throw new RuntimeError('The callable passed to "filter" filter must be a Closure in sandbox mode.');
1611-
}
1611+
twig_check_arrow_in_sandbox($env, $arrow, 'filter', 'filter');
16121612

16131613
if (\is_array($array)) {
16141614
return array_filter($array, $arrow, \ARRAY_FILTER_USE_BOTH);
@@ -1620,9 +1620,7 @@ function twig_array_filter(Environment $env, $array, $arrow)
16201620

16211621
function twig_array_map(Environment $env, $array, $arrow)
16221622
{
1623-
if (!$arrow instanceof Closure && $env->hasExtension('\Twig\Extension\SandboxExtension') && $env->getExtension('\Twig\Extension\SandboxExtension')->isSandboxed()) {
1624-
throw new RuntimeError('The callable passed to the "map" filter must be a Closure in sandbox mode.');
1625-
}
1623+
twig_check_arrow_in_sandbox($env, $arrow, 'map', 'filter');
16261624

16271625
$r = [];
16281626
foreach ($array as $k => $v) {
@@ -1634,9 +1632,7 @@ function twig_array_map(Environment $env, $array, $arrow)
16341632

16351633
function twig_array_reduce(Environment $env, $array, $arrow, $initial = null)
16361634
{
1637-
if (!$arrow instanceof Closure && $env->hasExtension('\Twig\Extension\SandboxExtension') && $env->getExtension('\Twig\Extension\SandboxExtension')->isSandboxed()) {
1638-
throw new RuntimeError('The callable passed to the "reduce" filter must be a Closure in sandbox mode.');
1639-
}
1635+
twig_check_arrow_in_sandbox($env, $arrow, 'reduce', 'filter');
16401636

16411637
if (!\is_array($array)) {
16421638
if (!$array instanceof \Traversable) {
@@ -1648,4 +1644,11 @@ function twig_array_reduce(Environment $env, $array, $arrow, $initial = null)
16481644

16491645
return array_reduce($array, $arrow, $initial);
16501646
}
1647+
1648+
function twig_check_arrow_in_sandbox(Environment $env, $arrow, $thing, $type)
1649+
{
1650+
if (!$arrow instanceof Closure && $env->hasExtension('\Twig\Extension\SandboxExtension') && $env->getExtension('\Twig\Extension\SandboxExtension')->isSandboxed()) {
1651+
throw new RuntimeError(sprintf('The callable passed to the "%s" %s must be a Closure in sandbox mode.', $thing, $type));
1652+
}
1653+
}
16511654
}

tests/Extension/SandboxTest.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ public function testSandboxDisabledAfterIncludeFunctionError()
390390
public function testSandboxWithNoClosureFilter()
391391
{
392392
$this->expectException('\Twig\Error\RuntimeError');
393-
$this->expectExceptionMessage('The callable passed to "filter" filter must be a Closure in sandbox mode in "index" at line 1.');
393+
$this->expectExceptionMessage('The callable passed to the "filter" filter must be a Closure in sandbox mode in "index" at line 1.');
394394

395395
$twig = $this->getEnvironment(true, ['autoescape' => 'html'], ['index' => <<<EOF
396396
{{ ["foo", "bar", ""]|filter("trim")|join(", ") }}

0 commit comments

Comments
 (0)