Skip to content

Commit

Permalink
Merge branch '2.x' into 3.x
Browse files Browse the repository at this point in the history
* 2.x:
  Disallow non closures in `sort` filter when the sanbox mode is enabled
  • Loading branch information
fabpot committed Feb 4, 2022
2 parents 25d410b + 22b9dc3 commit 9e5ca74
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 13 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# 3.3.8 (2022-XX-XX)

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

# 3.3.7 (2022-01-03)

Expand Down
25 changes: 14 additions & 11 deletions src/Extension/CoreExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ public function getFilters(): array
// array helpers
new TwigFilter('join', 'twig_join_filter'),
new TwigFilter('split', 'twig_split_filter', ['needs_environment' => true]),
new TwigFilter('sort', 'twig_sort_filter'),
new TwigFilter('sort', 'twig_sort_filter', ['needs_environment' => true]),
new TwigFilter('merge', 'twig_array_merge'),
new TwigFilter('batch', 'twig_array_batch'),
new TwigFilter('column', 'twig_array_column'),
Expand Down Expand Up @@ -887,7 +887,7 @@ function twig_reverse_filter(Environment $env, $item, $preserveKeys = false)
*
* @return array
*/
function twig_sort_filter($array, $arrow = null)
function twig_sort_filter(Environment $env, $array, $arrow = null)
{
if ($array instanceof \Traversable) {
$array = iterator_to_array($array);
Expand All @@ -896,6 +896,8 @@ function twig_sort_filter($array, $arrow = null)
}

if (null !== $arrow) {
twig_check_arrow_in_sandbox($env, $arrow, 'sort', 'filter');

uasort($array, $arrow);
} else {
asort($array);
Expand Down Expand Up @@ -1639,9 +1641,7 @@ function twig_array_filter(Environment $env, $array, $arrow)
throw new RuntimeError(sprintf('The "filter" filter expects an array or "Traversable", got "%s".', \is_object($array) ? \get_class($array) : \gettype($array)));
}

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

if (\is_array($array)) {
return array_filter($array, $arrow, \ARRAY_FILTER_USE_BOTH);
Expand All @@ -1653,9 +1653,7 @@ function twig_array_filter(Environment $env, $array, $arrow)

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

$r = [];
foreach ($array as $k => $v) {
Expand All @@ -1667,9 +1665,7 @@ function twig_array_map(Environment $env, $array, $arrow)

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

if (!\is_array($array)) {
if (!$array instanceof \Traversable) {
Expand All @@ -1681,4 +1677,11 @@ function twig_array_reduce(Environment $env, $array, $arrow, $initial = null)

return array_reduce($array, $arrow, $initial);
}

function twig_check_arrow_in_sandbox(Environment $env, $arrow, $thing, $type)
{
if (!$arrow instanceof Closure && $env->hasExtension('\Twig\Extension\SandboxExtension') && $env->getExtension('\Twig\Extension\SandboxExtension')->isSandboxed()) {
throw new RuntimeError(sprintf('The callable passed to the "%s" %s must be a Closure in sandbox mode.', $thing, $type));
}
}
}
2 changes: 1 addition & 1 deletion tests/Extension/SandboxTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ public function testSandboxDisabledAfterIncludeFunctionError()
public function testSandboxWithNoClosureFilter()
{
$this->expectException('\Twig\Error\RuntimeError');
$this->expectExceptionMessage('The callable passed to "filter" filter must be a Closure in sandbox mode in "index" at line 1.');
$this->expectExceptionMessage('The callable passed to the "filter" filter must be a Closure in sandbox mode in "index" at line 1.');

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

0 comments on commit 9e5ca74

Please sign in to comment.