mirror of
https://github.com/twigphp/Twig.git
synced 2026-09-14 03:16:34 +00:00
Merge branch '3.14.x' into 3.x
* 3.14.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.14.1 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
This commit is contained in:
@@ -41,6 +41,13 @@
|
||||
* Add the `enum` function
|
||||
* Add support for logical `xor` operator
|
||||
|
||||
# 3.14.1 (2024-11-06)
|
||||
|
||||
* [BC BREAK] Fix a security issue in the sandbox mode allowing an attacker to call attributes on Array-like objects
|
||||
They are now checked via the property policy
|
||||
* Fix a security issue in the sandbox mode allowing an attacker to be able to call `toString()`
|
||||
under some circumstances on an object even if the `__toString()` method is not allowed by the security policy
|
||||
|
||||
# 3.14.0 (2024-09-09)
|
||||
|
||||
* Fix a security issue when an included sandboxed template has been loaded before without the sandbox context
|
||||
@@ -87,6 +94,17 @@
|
||||
* Fix integration tests when a test has more than one data/expect section and deprecations
|
||||
* Add the `enum_cases` function
|
||||
|
||||
# 3.11.2 (2024-11-06)
|
||||
|
||||
* [BC BREAK] Fix a security issue in the sandbox mode allowing an attacker to call attributes on Array-like objects
|
||||
They are now checked via the property policy
|
||||
* Fix a security issue in the sandbox mode allowing an attacker to be able to call `toString()`
|
||||
under some circumstances on an object even if the `__toString()` method is not allowed by the security policy
|
||||
|
||||
# 3.11.1 (2024-09-10)
|
||||
|
||||
* Fix a security issue when an included sandboxed template has been loaded before without the sandbox context
|
||||
|
||||
# 3.11.0 (2024-08-08)
|
||||
|
||||
* Deprecate `OptimizerNodeVisitor::OPTIMIZE_RAW_FILTER`
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ won't be allowed and will generate a ``\Twig\Sandbox\SecurityError`` exception.
|
||||
|
||||
.. note::
|
||||
|
||||
As of Twig 1.14.1 (and on Twig 3.11.2), if the ``Article`` class implements
|
||||
As of Twig 3.14.1 (and on Twig 3.11.2), if the ``Article`` class implements
|
||||
the ``ArrayAccess`` interface, the templates will only be able to access
|
||||
the ``title`` and ``body`` attributes.
|
||||
|
||||
|
||||
@@ -98,8 +98,6 @@ use Twig\Util\CallableArgumentsExtractor;
|
||||
|
||||
final class CoreExtension extends AbstractExtension
|
||||
{
|
||||
private const DEFAULT_TRIM_CHARS = " \t\n\r\0\x0B";
|
||||
|
||||
public const ARRAY_LIKE_CLASSES = [
|
||||
'ArrayIterator',
|
||||
'ArrayObject',
|
||||
@@ -114,6 +112,8 @@ final class CoreExtension extends AbstractExtension
|
||||
'WeakMap',
|
||||
];
|
||||
|
||||
private const DEFAULT_TRIM_CHARS = " \t\n\r\0\x0B";
|
||||
|
||||
private $dateFormats = ['F j, Y H:i', '%d days'];
|
||||
private $numberFormat = [0, '.', ','];
|
||||
private $timezone = null;
|
||||
@@ -1744,10 +1744,6 @@ final class CoreExtension extends AbstractExtension
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($sandboxed) {
|
||||
$env->getExtension(SandboxExtension::class)->checkPropertyAllowed($object, $item, $lineno, $source);
|
||||
}
|
||||
|
||||
return \constant($object::class.'::'.$item);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,14 +120,12 @@ final class SandboxExtension extends AbstractExtension
|
||||
public function ensureToStringAllowed($obj, int $lineno = -1, ?Source $source = null)
|
||||
{
|
||||
if (\is_array($obj)) {
|
||||
foreach ($obj as $v) {
|
||||
$this->ensureToStringAllowed($v, $lineno, $source);
|
||||
}
|
||||
$this->ensureToStringAllowedForArray($obj, $lineno, $source);
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
if ($this->isSandboxed($source) && $obj instanceof \Stringable) {
|
||||
if ($obj instanceof \Stringable && $this->isSandboxed($source)) {
|
||||
try {
|
||||
$this->policy->checkMethodAllowed($obj, '__toString');
|
||||
} catch (SecurityNotAllowedMethodError $e) {
|
||||
@@ -140,4 +138,28 @@ final class SandboxExtension extends AbstractExtension
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
private function ensureToStringAllowedForArray(array $obj, int $lineno, ?Source $source, array &$stack = []): void
|
||||
{
|
||||
foreach ($obj as $k => $v) {
|
||||
if (!$v) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!\is_array($v)) {
|
||||
$this->ensureToStringAllowed($v, $lineno, $source);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($r = \ReflectionReference::fromArrayElement($obj, $k)) {
|
||||
if (isset($stack[$r->getId()])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$stack[$r->getId()] = true;
|
||||
}
|
||||
|
||||
$this->ensureToStringAllowedForArray($v, $lineno, $source, $stack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,10 @@ class SandboxTest extends TestCase
|
||||
'some_array' => [5, 6, 7, new FooObject()],
|
||||
'array_like' => new ArrayLikeObject(),
|
||||
'magic' => new MagicObject(),
|
||||
'recursion' => [4],
|
||||
];
|
||||
self::$params['recursion'][] = &self::$params['recursion'];
|
||||
self::$params['recursion'][] = new FooObject();
|
||||
|
||||
self::$templates = [
|
||||
'1_basic1' => '{{ obj.foo }}',
|
||||
@@ -317,6 +320,7 @@ class SandboxTest extends TestCase
|
||||
'context' => ['{{ _context|join(", ") }}'],
|
||||
'spread_array_operator' => ['{{ [1, 2, ...[5, 6, 7, obj]]|join(",") }}'],
|
||||
'spread_array_operator_var' => ['{{ [1, 2, ...some_array]|join(",") }}'],
|
||||
'recursion' => ['{{ recursion|join(", ") }}'],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -650,12 +654,12 @@ class ArrayLikeObject extends \ArrayObject
|
||||
{
|
||||
public function offsetExists($offset): bool
|
||||
{
|
||||
throw new \BadMethodCallException('Should not be called');
|
||||
throw new \BadMethodCallException('Should not be called.');
|
||||
}
|
||||
|
||||
public function offsetGet($offset): mixed
|
||||
{
|
||||
throw new \BadMethodCallException('Should not be called');
|
||||
throw new \BadMethodCallException('Should not be called.');
|
||||
}
|
||||
|
||||
public function offsetSet($offset, $value): void
|
||||
@@ -671,11 +675,11 @@ class MagicObject
|
||||
{
|
||||
public function __get($name): mixed
|
||||
{
|
||||
throw new \BadMethodCallException('Should not be called');
|
||||
throw new \BadMethodCallException('Should not be called.');
|
||||
}
|
||||
|
||||
public function __isset($name): bool
|
||||
{
|
||||
throw new \BadMethodCallException('Should not be called');
|
||||
throw new \BadMethodCallException('Should not be called.');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user