Commit Graph

411 Commits

Author SHA1 Message Date
Fabien Potencier b53e100444 Nested macro imports 2026-08-03 10:30:32 +02:00
Fabien Potencier 34d9c67d38 Deprecate using parentheses when testing a macro with the defined test 2026-07-31 12:09:23 +02:00
Fabien Potencier d7f8b4eb1c Redesign macro calls and argument handling 2026-07-30 13:53:24 +02:00
Fabien Potencier b762bc94b9 Make the sandbox a first-class citizen with a dedicated Sandbox class 2026-07-30 12:05:47 +02:00
Fabien Potencier ad305b414e Deprecate macro calls without parentheses 2026-07-28 16:13:23 +02:00
Fabien Potencier be36fee09e Rename macro variable AST nodes 2026-07-28 11:53:50 +02:00
Fabien Potencier 6ce5beb7c2 Normalize destructuring assignment targets 2026-07-27 18:51:15 +02:00
Fabien Potencier 0b8e267bce Fix CS 2026-07-12 15:21:32 +02:00
Fabien Potencier 9c6d76b61c Add void return type hint even in tests 2026-07-12 13:43:08 +02:00
Fabien Potencier 679b8fd610 Fix array access with a Stringable key on ArrayAccess objects using object keys 2026-07-06 22:42:11 +02:00
Fabien Potencier 0d283d304a Throw a SyntaxError instead of a PHP fatal error when a macro argument is defined twice 2026-07-04 11:17:28 +02:00
Alexander Pankratov f5afaabf54 Fix Markup truthiness in boolean expressions 2026-06-11 15:33:21 +02:00
Fabien Potencier c12100525e Introduce a CorrectnessNodeVisitor to validate that templates are semantically correct 2026-06-11 07:43:33 +02:00
Fabien Potencier 612dc96c18 feature #4838 Allow calling a macro with a dynamic name via the dot operator (fabpot)
This PR was merged into the 3.x branch.

Discussion
----------

Allow calling a macro with a dynamic name via the dot operator

Closes #4715

Commits
-------

87093aab9e Allow calling a macro with a dynamic name via the dot operator
2026-06-07 09:36:06 +02:00
Fabien Potencier 87093aab9e Allow calling a macro with a dynamic name via the dot operator 2026-06-06 17:10:52 +02:00
Fabien Potencier aef7587fc8 feature #4819 Add an allow-list for tests to the sandbox security policy (fabpot)
This PR was merged into the 3.x branch.

Discussion
----------

Add an allow-list for tests to the sandbox security policy

Commits
-------

416d07da1d Add an allow-list for tests to the sandbox security policy
2026-06-06 17:04:39 +02:00
Fabien Potencier 416d07da1d Add an allow-list for tests to the sandbox security policy 2026-06-06 11:08:56 +02:00
Fabien Potencier 0197736dfc Reduce memory usage of the context restoration compiled at the end of for loops 2026-06-06 09:31:56 +02:00
Fabien Potencier 89f886e324 Skip the string cast in PrintNode when the expression is already a string and add tests 2026-06-03 19:56:27 +02:00
Christophe Coevoet 86840f9351 Ensure PrintNode is yielding string content 2026-06-03 19:56:11 +02:00
Fabien Potencier 6d5ef30436 Skip the sandbox __toString check on arguments whose PHP parameter type cannot implicitly coerce to string 2026-06-02 13:58:24 +02:00
Fabien Potencier 8ec9530732 Fix inconsistent array access with a Stringable key 2026-05-29 10:06:57 +02:00
Fabien Potencier 23eb6eb126 Fix sandbox filter/tag/function allow-list bypass when sandbox state changes between renders 2026-05-27 14:59:42 +02:00
Fabien Potencier 9ff4101463 Fix sandbox __toString policy bypass via dynamic mapping keys 2026-05-27 14:54:34 +02:00
Fabien Potencier 8d6af0707b Fix sandbox __toString bypass via the in and not in operators 2026-05-27 14:52:32 +02:00
Fabien Potencier 49e59e4612 Simplify code 2026-05-24 09:57:49 +02:00
Fabien Potencier 447d0b2331 Fix sandbox __toString bypasses 2026-05-20 00:18:59 +02:00
Fabien Potencier ea3f7a2844 Validate macro name in MacroReferenceExpression constructor
The name passed to MacroReferenceExpression is emitted as raw PHP in
compile() via "->{$name}(...)". Callers were expected to validate
the name, but a missing check led to CVE-2026-XXXXX (PHP code injection
via _self / import macro reference): defense-in-depth, validate the
name in the constructor so the class is safe by construction.
2026-05-19 23:42:31 +02:00
Alexandre Daubois 819c6a89fe Fix sandbox bypass in the {% sandbox %} tag when including a preloaded template 2026-05-19 23:00:58 +02:00
Alexandre Daubois e9ff55f691 Fix sandbox bypass: PHP code injection via {% use %} template name 2026-05-19 22:50:45 +02:00
Fabien Potencier a8eb5a8a74 security #cve-2026-46639 Fix sandbox bypass in object destructuring assignment (alexandre-daubois)
This PR was merged into the twig-3.x branch.
2026-05-19 21:37:04 +02:00
Fabien Potencier d0579ededc Fix sandbox bypass: propagate sandbox state to checkArrow for source-policy sandboxing 2026-05-16 18:56:08 +01:00
Fabien Potencier 5462817da0 Add a needs_is_sandboxed option for filters, functions, and tests 2026-05-16 18:52:17 +01:00
Alexandre Daubois 3fe13f98f8 Fix sandbox bypass in object destructuring assignment 2026-04-28 12:59:06 +02:00
Fabien Potencier efa004caab Fix null coalescing operator with imported macros 2026-02-25 08:38:54 +01:00
Fabien Potencier dcfc419a25 Enforce more precise type on ListExpression 2026-02-23 13:36:14 +01:00
Fabien Potencier 379fb2faca Deprecate passing non AbstractExpression nodes to MatchesBinary 2026-02-23 11:40:51 +01:00
Fabien Potencier 751a187f07 feature #4748 Support short-circuiting in null-safe operator chains (HypeMC)
This PR was merged into the 3.x branch.

Discussion
----------

Support short-circuiting in null-safe operator chains

This PR adds short-circuiting for null-safe operator chains, using the same rules as PHP, `PropertyAccess`, and the `ExpressionLanguage`.

Previously, only the immediate null-safe access was guarded. With this change, as soon as a `null` is encountered at a null-safe access, the rest of the chain is skipped.

My approach was to move the null check outside of the `getAttribute()` calls so the expression can immediately return `null`, eg:

```twig
foo?.bar.baz
```

Before:

```php
yield $this->env
    ->getRuntime('Twig\Runtime\EscaperRuntime')
    ->escape(
        CoreExtension::getAttribute(
            $this->env,
            $this->source,
            (
                null === (
                    $_v0 = (
                        isset($context['foo']) || array_key_exists('foo', $context)
                            ? $context['foo']
                            : throw new RuntimeError('Variable "foo" does not exist.', 3, $this->source)
                    )
                )
                    ? null
                    : CoreExtension::getAttribute(
                        $this->env,
                        $this->source,
                        $_v0,
                        'bar',
                        [],
                        'any',
                        false,
                        false,
                        false,
                        3
                    )
            ),
            'baz',
            [],
            'any',
            false,
            false,
            false,
            3
        ),
        'html',
        null,
        true
    );
```

Now:

```php
yield $this->env
    ->getRuntime('Twig\Runtime\EscaperRuntime')
    ->escape(
        (
            null === (
                $_v0 = (
                    isset($context['foo']) || array_key_exists('foo', $context)
                        ? $context['foo']
                        : throw new RuntimeError('Variable "foo" does not exist.', 3, $this->source)
                )
            )
                ? null
                : CoreExtension::getAttribute(
                    $this->env,
                    $this->source,
                    CoreExtension::getAttribute(
                        $this->env,
                        $this->source,
                        $_v0,
                        'bar',
                        [],
                        'any',
                        false,
                        false,
                        false,
                        3
                    ),
                    'baz',
                    [],
                    'any',
                    false,
                    false,
                    false,
                    3
                )
        ),
        'html',
        null,
        true
    );
```

Commits
-------

d56e8e2dba Support short-circuiting in null-safe operator chains
2026-02-08 19:02:03 +01:00
Fabien Potencier df893829f2 feature #4759 Add support for renaming variables in object destructuring (fabpot)
This PR was merged into the 3.x branch.

Discussion
----------

Add support for renaming variables in object destructuring

Closes #4747

Commits
-------

3cc1b5233c Add support for renaming variables in object destructuring
2026-02-07 14:22:40 +01:00
Fabien Potencier 861215c507 Fix CS 2026-02-07 09:07:38 +01:00
HypeMC d56e8e2dba Support short-circuiting in null-safe operator chains 2026-02-06 22:36:57 +01:00
Fabien Potencier 3cc1b5233c Add support for renaming variables in object destructuring 2026-02-06 22:12:59 +01:00
Fabien Potencier 8a0f8acbdf Add support for object and mapping destructuring 2026-01-21 13:21:14 +01:00
Fabien Potencier 76c404ec67 Rename classes 2026-01-21 13:14:16 +01:00
Fabien Potencier bb99af3b39 Assignment operator array destructuring 2026-01-21 08:46:28 +01:00
Fabien Potencier bfbbef05f2 Add the = assignment operator 2026-01-19 16:39:57 +01:00
Fabien Potencier 6904954165 Tweak null-safe operator implementation 2026-01-17 15:11:37 +01:00
Felds Liscia 263c04fd1f Add null-safe operator 2026-01-17 14:57:47 +01:00
Fabien Potencier 94c8bdd6a6 Add === and !== operators 2026-01-14 09:58:48 +01:00
Simon André e4d7915702 Compile 'index' with repr (not string) in EmbedNode
Before this fix, the generated Template code had quotes around the
index (integer) parameter value.
2025-09-25 08:28:51 +02:00