Skip to content

Commit 83a21d3

Browse files
committedNov 7, 2024
Merge branch '3.11.x' into 3.14.x
* 3.11.x: Improve detection of recursion Fix recursion when arrays contain self-references in sandboxed mode Fix code Prepare the 3.11.2 release Update CHANGELOG Sandbox ArrayAccess and do sandbox checks before isset() checks Fix sandbox handling for __toString() Prepare the 3.11.1 release Fix a security issue when an included sandboxed template has been loaded before without the sandbox context
2 parents f405356 + d3fc074 commit 83a21d3

File tree

4 files changed

+47
-10
lines changed

4 files changed

+47
-10
lines changed
 

‎CHANGELOG

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# 3.14.1 (2024-11-06)
22

3-
* [BC BREAK] Fix a security issue in the sandbox mode allowing an attacker to call attributes on Array-like objects
3+
* [BC BREAK] Fix a security issue in the sandbox mode allowing an attacker to call attributes on Array-like objects
44
They are now checked via the property policy
55
* Fix a security issue in the sandbox mode allowing an attacker to be able to call `toString()`
66
under some circumstances on an object even if the `__toString()` method is not allowed by the security policy
@@ -51,6 +51,17 @@
5151
* Fix integration tests when a test has more than one data/expect section and deprecations
5252
* Add the `enum_cases` function
5353

54+
# 3.11.2 (2024-11-06)
55+
56+
* [BC BREAK] Fix a security issue in the sandbox mode allowing an attacker to call attributes on Array-like objects
57+
They are now checked via the property policy
58+
* Fix a security issue in the sandbox mode allowing an attacker to be able to call `toString()`
59+
under some circumstances on an object even if the `__toString()` method is not allowed by the security policy
60+
61+
# 3.11.1 (2024-09-10)
62+
63+
* Fix a security issue when an included sandboxed template has been loaded before without the sandbox context
64+
5465
# 3.11.0 (2024-08-08)
5566

5667
* Deprecate `OptimizerNodeVisitor::OPTIMIZE_RAW_FILTER`

‎doc/api.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,7 @@ won't be allowed and will generate a ``\Twig\Sandbox\SecurityError`` exception.
488488

489489
.. note::
490490

491-
As of Twig 1.14.1 (and on Twig 3.11.2), if the ``Article`` class implements
491+
As of Twig 3.14.1 (and on Twig 3.11.2), if the ``Article`` class implements
492492
the ``ArrayAccess`` interface, the templates will only be able to access
493493
the ``title`` and ``body`` attributes.
494494

‎src/Extension/SandboxExtension.php

+26-4
Original file line numberDiff line numberDiff line change
@@ -120,14 +120,12 @@ public function checkPropertyAllowed($obj, $property, int $lineno = -1, ?Source
120120
public function ensureToStringAllowed($obj, int $lineno = -1, ?Source $source = null)
121121
{
122122
if (\is_array($obj)) {
123-
foreach ($obj as $v) {
124-
$this->ensureToStringAllowed($v, $lineno, $source);
125-
}
123+
$this->ensureToStringAllowedForArray($obj, $lineno, $source);
126124

127125
return $obj;
128126
}
129127

130-
if ($this->isSandboxed($source) && $obj instanceof \Stringable) {
128+
if ($obj instanceof \Stringable && $this->isSandboxed($source)) {
131129
try {
132130
$this->policy->checkMethodAllowed($obj, '__toString');
133131
} catch (SecurityNotAllowedMethodError $e) {
@@ -140,4 +138,28 @@ public function ensureToStringAllowed($obj, int $lineno = -1, ?Source $source =
140138

141139
return $obj;
142140
}
141+
142+
private function ensureToStringAllowedForArray(array $obj, int $lineno, ?Source $source, array &$stack = []): void
143+
{
144+
foreach ($obj as $k => $v) {
145+
if (!$v) {
146+
continue;
147+
}
148+
149+
if (!\is_array($v)) {
150+
$this->ensureToStringAllowed($v, $lineno, $source);
151+
continue;
152+
}
153+
154+
if ($r = \ReflectionReference::fromArrayElement($obj, $k)) {
155+
if (isset($stack[$r->getId()])) {
156+
continue;
157+
}
158+
159+
$stack[$r->getId()] = true;
160+
}
161+
162+
$this->ensureToStringAllowedForArray($v, $lineno, $source, $stack);
163+
}
164+
}
143165
}

‎tests/Extension/SandboxTest.php

+8-4
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,10 @@ protected function setUp(): void
4545
'some_array' => [5, 6, 7, new FooObject()],
4646
'array_like' => new ArrayLikeObject(),
4747
'magic' => new MagicObject(),
48+
'recursion' => [4],
4849
];
50+
self::$params['recursion'][] = &self::$params['recursion'];
51+
self::$params['recursion'][] = new FooObject();
4952

5053
self::$templates = [
5154
'1_basic1' => '{{ obj.foo }}',
@@ -302,6 +305,7 @@ public static function getSandboxUnallowedToStringTests()
302305
'context' => ['{{ _context|join(", ") }}'],
303306
'spread_array_operator' => ['{{ [1, 2, ...[5, 6, 7, obj]]|join(",") }}'],
304307
'spread_array_operator_var' => ['{{ [1, 2, ...some_array]|join(",") }}'],
308+
'recursion' => ['{{ recursion|join(", ") }}'],
305309
];
306310
}
307311

@@ -635,12 +639,12 @@ class ArrayLikeObject extends \ArrayObject
635639
{
636640
public function offsetExists($offset): bool
637641
{
638-
throw new \BadMethodCallException('Should not be called');
642+
throw new \BadMethodCallException('Should not be called.');
639643
}
640644

641645
public function offsetGet($offset): mixed
642646
{
643-
throw new \BadMethodCallException('Should not be called');
647+
throw new \BadMethodCallException('Should not be called.');
644648
}
645649

646650
public function offsetSet($offset, $value): void
@@ -656,11 +660,11 @@ class MagicObject
656660
{
657661
public function __get($name): mixed
658662
{
659-
throw new \BadMethodCallException('Should not be called');
663+
throw new \BadMethodCallException('Should not be called.');
660664
}
661665

662666
public function __isset($name): bool
663667
{
664-
throw new \BadMethodCallException('Should not be called');
668+
throw new \BadMethodCallException('Should not be called.');
665669
}
666670
}

0 commit comments

Comments
 (0)