Commit Graph

753 Commits

Author SHA1 Message Date
Fabien Potencier b91dbaa1ba Fix merge conflict resolution 2026-05-21 14:11:53 +02:00
Fabien Potencier 8dd0383353 Merge branch '3.x' into 4.x
* 3.x: (23 commits)
  Bump version
  Prepare the 3.26.0 release
  Update CHANGELOG
  Document that the sandbox doesn't protect against resource exhaustion
  Document template_from_string caveats when used in a sandboxed env
  Pre-escape HTML input on the `spaceless` filter
  Add docs on Markup about the goal of this class in the context of a sandbox
  Fix sandbox bypass in the "column" filter
  Fix sandbox `__toString` bypasses
  Validate macro name in MacroReferenceExpression constructor
  Fix sandbox bypass: PHP code injection via _self / import macro reference
  Fix deprecations in tests
  Fix sandbox bypass in the `{% sandbox %}` tag when including a preloaded template
  Encode single quotes as \x27 in Compiler::string()
  Fix sandbox bypass: PHP code injection via {% use %} template name
  Fix unbounded memoisation of `IntlDateFormatter` / `NumberFormatter`
  Fix deprecation
  [Profiler] Escape template and profile names in HtmlDumper
  Bump version
  Fix sandbox bypass: propagate sandbox state to checkArrow for source-policy sandboxing
  ...

# Conflicts:
#	CHANGELOG
#	doc/filters/spaceless.rst
#	extra/cssinliner-extra/CssInlinerExtension.php
#	extra/inky-extra/InkyExtension.php
#	extra/markdown-extra/MarkdownExtension.php
#	src/Environment.php
#	src/ExpressionParser/Infix/DotExpressionParser.php
#	src/Extension/CoreExtension.php
#	src/Node/Expression/FilterExpression.php
#	src/Node/Expression/FunctionExpression.php
#	src/Node/Expression/TestExpression.php
#	src/Node/ModuleNode.php
#	src/NodeVisitor/SandboxNodeVisitor.php
#	src/Resources/core.php
#	src/TokenParser/SandboxTokenParser.php
#	tests/Extension/SandboxTest.php
2026-05-21 13:58:45 +02:00
Fabien Potencier 3190b9ae12 Pre-escape HTML input on the spaceless filter 2026-05-20 08:29:48 +02:00
Alexandre Daubois f05c5011c2 Fix sandbox bypass in the "column" filter 2026-05-20 07:33:52 +02:00
Fabien Potencier 2e4b6d286e security #cve-2026-47732 [Sandbox] Fix __toString() support (fabpot)
This PR was merged into the twig-3.x branch.
2026-05-20 07:31:34 +02:00
Fabien Potencier 3464990a51 security #cve-2026-47730 [Profiler] Escape template and profile names in HtmlDumper (nicolas-grekas)
This PR was merged into the twig-3.x branch.
2026-05-20 07:31:01 +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 324fa60545 Fix sandbox bypass: PHP code injection via _self / import macro reference 2026-05-19 23:41:59 +02:00
Fabien Potencier aeb37f4801 Fix deprecations in tests 2026-05-19 23:05:30 +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
Fabien Potencier 679447fa29 Encode single quotes as \x27 in Compiler::string()
This is a defense-in-depth measure: callers must always concatenate the
result into a double-quoted PHP context, but if one ever (mistakenly)
embeds it inside a single-quoted PHP literal, an attacker-controlled
single quote in the source value could break out of that context. The
previous commit fixed exactly such a bug in ModuleNode for the {% use %}
template name.

Encoding ' as the hex escape \x27 guarantees that the emitted PHP source
never contains a literal single quote derived from user input, while the
decoded runtime value is unchanged. \' is not used because it is not a
recognized escape sequence in PHP double-quoted strings (the backslash
would be kept literally).
2026-05-19 22:58:27 +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 e494400ce4 Fix deprecation 2026-05-19 22:05:26 +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 c8dfd62064 security #cve-2026-24425 Fix sandbox bypass: propagate Source to checkArrow for source-policy sandboxing (fabpot)
This PR was merged into the twig-3.x branch.
2026-05-19 21:30:51 +02:00
Nicolas Grekas a5f6e8793e [Profiler] Escape template and profile names in HtmlDumper
The HtmlDumper output is intended to be rendered in a browser, and the
template and macro/block names it interpolates are loader-controlled
(e.g. the key for ArrayLoader or a database row id), so they can carry
arbitrary HTML when an application stores templates under user-supplied
identifiers.
2026-05-19 18:54:32 +02:00
Fabien Potencier 0c515667d2 Merge remote-tracking branch 'origin/3.x' into 4.x
* origin/3.x:
  Add a `needs_is_sandboxed` option for filters, functions, and tests
  Bump version
  Make embeds deterministic
  [Doc] Document loose comparison in the `in` operator
  [Doc] Reword whitespace control note about first-newline removal
  Stop publishing extra package minor versions with no changes
  Lazy load EscaperRuntime in EscaperExtension
  Fix typo
  Replace parent-child analogy in `doc/tags/extends.rst`
  doc: Add missing toctree entries and fix ordering
  Fix CHANGELOG
  Bump version
  Prepare the 3.24.0 release
2026-05-17 08:18:04 +01:00
Fabien Potencier fd0760d972 feature #4795 Lazy load EscaperRuntime in EscaperExtension (GromNaN)
This PR was merged into the 3.x branch.

Discussion
----------

Lazy load `EscaperRuntime` in `EscaperExtension`

This allows overriding `EscaperRuntime` via a custom runtime loader.

Previously, `EscaperExtension::setEnvironment()` was calling `$environment->getRuntime(EscaperRuntime::class)` eagerly. Since this method is called from `Environment::__construct()`, the runtime was resolved before any custom runtime loader could be injected, making it impossible to override `EscaperRuntime`.

- Required by https://github.com/symfony/symfony/pull/63929

Commits
-------

b73ab8cfd9 Lazy load EscaperRuntime in EscaperExtension
2026-05-17 07:52:38 +01: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
itsalmostchristmas 2b4aa4458a Make embeds deterministic 2026-05-16 09:48:23 +01:00
Jérôme Tamarelle b73ab8cfd9 Lazy load EscaperRuntime in EscaperExtension
Previously, setEnvironment() called getRuntime(EscaperRuntime::class) eagerly,
which prevented overriding EscaperRuntime via a custom runtime loader since
Environment::__construct() calls setEnvironment() before any loader can be injected.
2026-04-30 13:43:11 +02:00
Alexandre Daubois 3fe13f98f8 Fix sandbox bypass in object destructuring assignment 2026-04-28 12:59:06 +02:00
Fabien Potencier 4ff99377f5 Merge branch '3.x' into 4.x
* 3.x:
  Fix null coalescing operator with imported macros
2026-02-25 10:39:52 +01:00
Fabien Potencier e56cdfdded bug #4778 Fix null coalescing operator with imported macros (fabpot)
This PR was merged into the 3.x branch.

Discussion
----------

Fix null coalescing operator with imported macros

Closes #4776

When using the null coalescing operator with a macro imported via the `from` tag, the `TemplateVariable` node inside `MacroReferenceExpression` was deep-cloned, causing the clone to generate a different `$macros` key than the one assigned by `AssignTemplateVariable`. This resulted in a `Call to a member function hasMacro() on null` error.

Commits
-------

efa004caab Fix null coalescing operator with imported macros
2026-02-25 10:38:36 +01:00
Fabien Potencier b8e6b314b3 Merge branch '3.x' into 4.x
* 3.x:
  fix documentation typos for singular filter arguments
  Add getOperatorTokens() to ExpressionParserInterface to separate operator token registration from parser identity
  Ensure filters/attributes aren't mistaken for operators
2026-02-25 09:40:35 +01:00
Fabien Potencier efa004caab Fix null coalescing operator with imported macros 2026-02-25 08:38:54 +01:00
Fabien Potencier e5eb95d0d7 Add getOperatorTokens() to ExpressionParserInterface to separate operator token registration from parser identity 2026-02-24 21:13:06 +01:00
brandonkelly a9ac993938 Ensure filters/attributes aren't mistaken for operators 2026-02-24 21:10:18 +01:00
Fabien Potencier b9d578d53f Merge branch '3.x' into 4.x
* 3.x:
  Deprecate passing a non-AbstractExpression node to Parser::setParent()
2026-02-23 11:13:55 +01:00
Fabien Potencier 54d5c004b4 Deprecate passing a non-AbstractExpression node to Parser::setParent() 2026-02-22 15:28:59 +01:00
Fabien Potencier 9a198ce169 Fix tests 2026-02-09 12:32:40 +01:00
Fabien Potencier 463ef4018d Merge branch '3.x' into 4.x
* 3.x:
  Update CHANGELOG
  Add `html_attr_relaxed` escaping strategy
  re-add mixed return type
  Support short-circuiting in null-safe operator chains
  Add support for renaming variables in object destructuring
  Update .gitattributes to remove splitsh.json
  Fix intro for operator precedence table ?
2026-02-09 12:29:34 +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
Matthias Pigulla 04aa3df49f Add html_attr_relaxed escaping strategy 2026-02-08 18:59:07 +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 2fba06cba9 Fix tests 2026-02-07 09:18:21 +01:00
Fabien Potencier cdce18d02a Fix CS 2026-02-07 09:16:06 +01:00
Fabien Potencier 0facb551b0 Merge branch '3.x' into 4.x
* 3.x:
  Fix CS
2026-02-07 09:12:05 +01:00
Fabien Potencier 861215c507 Fix CS 2026-02-07 09:07:38 +01:00
Fabien Potencier 0222460a72 Merge branch '3.x' into 4.x
* 3.x:
  Bump version
  Add a not about the return value of destructuring
  Fix null-safe operator test
  Bump version
  Prepare the  release
  Update CHANGELOG
  Add support for object and mapping destructuring
  Rename classes
  Assignment operator array destructuring
  Fix doc notes
  Fix doc notes
  Add the = assignment operator
  Fix grammar and spelling mistakes in documentation
2026-02-06 22:45:48 +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
HypeMC a16ac6bd35 Fix null-safe operator test 2026-01-25 04:57:19 +01:00
Fabien Potencier 8a0f8acbdf Add support for object and mapping destructuring 2026-01-21 13:21:14 +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 e968cf6591 Merge branch '3.x' into 4.x
* 3.x:
  Tweak null-safe operator implementation
  Add null-safe operator
  Update u.rst to clarify truncate method's third argument behavior
2026-01-17 15:17:13 +01:00
Felds Liscia 263c04fd1f Add null-safe operator 2026-01-17 14:57:47 +01:00