Ce mail provient de l'extérieur, restons vigilants

=====================================================================

                            CERT-Renater

                Note d'Information No. 2026/VULN530
_____________________________________________________________________

DATE                : 21/05/2026

HARDWARE PLATFORM(S): /

OPERATING SYSTEM(S): Systems running Twig (Composer) versions prior
                                      to 3.26.0.

=====================================================================
https://github.com/twigphp/Twig/security/advisories/GHSA-7p85-w9px-jpjp
https://github.com/twigphp/Twig/security/advisories/GHSA-45vw-wh46-2vx8
https://github.com/twigphp/Twig/security/advisories/GHSA-pr2w-4gpj-cpq4
https://github.com/twigphp/Twig/security/advisories/GHSA-mm6w-gr99-p3jj
https://github.com/twigphp/Twig/security/advisories/GHSA-2q52-x2ff-qgfr
https://github.com/twigphp/Twig/security/advisories/GHSA-923g-j88x-j34q
https://github.com/twigphp/Twig/security/advisories/GHSA-7fxw-r6jv-74c8
https://github.com/twigphp/Twig/security/advisories/GHSA-24x9-r6q4-q93w
https://github.com/twigphp/Twig/security/advisories/GHSA-vcc8-phrv-43wj
_____________________________________________________________________


PHP code injection via `{% use %}` template name
Critical
nicolas-grekas published GHSA-7p85-w9px-jpjp May 20, 2026

Package
twig/twig (Composer)

Affected versions
< 3.26.0

Patched versions
3.26.0


Description

Description

Compiler::string() escapes ", $, \, NUL and TAB when generating PHP
double-quoted string literals, but does not escape single quotes.
In ModuleNode::compileConstructor(), the template name from a
{% use %} tag is compiled via subcompile() -> string() and placed
inside a surrounding PHP single-quoted string literal. A template
name containing a single quote terminates that surrounding string
early, allowing arbitrary PHP expressions to be injected into the
compiled cache file.

The injected code executes within the PHP process when the cache
file is first loaded, bypassing the Twig sandbox entirely and
achieving remote code execution. SecurityPolicy unconditionally
allows {% use %} regardless of the configured allowedTags, so
this primitive is reachable from sandboxed templates as well.


Resolution

Compiler::string() now also escapes single quotes so that template
names placed inside single-quoted PHP literals can no longer
break out of the surrounding context.


Credits

We would like to thank Anvil Secure in collaboration with Claude
and Anthropic Research for reporting the issue and providing the
fix.


Severity
Critical

CVE ID
CVE-2026-46633

Weaknesses
Weakness CWE-94 

_____________________________________________________________________


Arbitrary PHP code execution via `_self.(<string>)` macro-reference
compilation

Critical
nicolas-grekas published GHSA-45vw-wh46-2vx8 May 20, 2026

Package
twig/twig (Composer)

Affected versions
>= 3.15.0, < 3.26.0

Patched versions
3.26.0


Description

Description

The obj.(expr) dynamic-attribute syntax (added in 3.15.0 as the
replacement for the deprecated attribute() function) lets the
attribute be an arbitrary expression. When the receiver
is _self (or any {% import %} alias) and the parenthesised
expression is a string literal, DotExpressionParser short-circuits
to the macro-call path and concatenates the attacker-controlled
string into a MacroReferenceExpression name with no identifier
validation. MacroReferenceExpression::compile() then emits that
name raw into the generated PHP source.

An attacker who can supply template source can inject arbitrary
PHP into the compiled template and execute it at template-load
time, before checkSecurity() is ever called. This is a complete
bypass of SandboxExtension, including a globally-enabled sandbox
with an empty SecurityPolicy allowlist.


Resolution

The parser now validates that the dynamic attribute resolves to
a valid macro identifier before routing through
MacroReferenceExpression, and the macro-reference compiler
emits the name through a properly escaped path.


Credits

We would like to thank Claude Mythos Preview (via Project Glasswing)
for reporting the issue and providing the fix.

Severity
Critical

CVE ID
CVE-2026-46640

Weaknesses
Weakness CWE-94 

_____________________________________________________________________


Sandbox: multiple `__toString()` policy bypasses via unguarded string
coercion points

High
nicolas-grekas published GHSA-pr2w-4gpj-cpq4 May 20, 2026

Package
twig/twig (Composer)

Affected versions
<= 3.25.0

Patched versions
3.26.0


Description

Description

SandboxNodeVisitor enforces SecurityPolicy::checkMethodAllowed() for
implicit __toString() calls by wrapping selected AST nodes in
CheckToStringNode. The set of wrapped nodes is incomplete, and
several Twig language constructs still trigger PHP string coercion
on a Stringable operand without first consulting the policy. A
sandboxed template author can therefore invoke __toString() on any
object reachable in the render context, even when __toString on its
class is not allowlisted.

Confirmed bypass vectors:

    Conditional expressions (a ? b : c, a ?: b, a ?? b) used as the
input of a string-coercing filter or as a filter/function argument.
    The matches operator and the loose comparison operators
(==, !=, <, >, <=, >=, <=>), which coerce a Stringable operand to
string and can be used as an oracle to recover the value byte by
byte (no tag, filter or function needs to be allowlisted).
    Twig tests in general (which were never policy-gated), in
particular is empty which casts a Stringable value
via (string) $value in CoreExtension::testEmpty().
    Null-coalesce expressions nested in concatenation, and the
direct output of allowed functions or filters that return a
Stringable object.
    Arguments passed to allowed object methods, template-name
expressions of template-loading tags (include, extends, use, ...),
dynamic attribute/property names, and spread arguments
from Traversable objects.
    The do tag and the .. range operator.

Resolution

The sandbox now wraps every child node that the parent will
string-coerce at runtime, instead of relying on a hardcoded
list of node types in SandboxNodeVisitor. A new
Twig\Node\CoercesChildrenToStringInterface lets nodes declare
which of their children must be guarded; core nodes
(concatenation, comparison and range binaries,
filter/function/test expressions, do, include, extends, use, ...)
implement it. Spread arguments are materialised and
policy-checked via the new SandboxExtension::ensureSpreadAllowed(),
and dynamic attribute names are checked at runtime inside
CoreExtension::getAttribute().


Credits

We would like to thank Anthropic Glasswing and El Kharoubi Iosif
for reporting the issues, and Fabien Potencier for providing
the fixes.

Severity
High

CVE ID
CVE-2026-47732

Weaknesses
No CWEs

Credits

    @fabpot fabpot Remediation developer


_____________________________________________________________________

Sandbox property and method bypass via object-destructuring assignment
High
nicolas-grekas published GHSA-mm6w-gr99-p3jj May 20, 2026

Package
twig/twig (Composer)

Affected versions
>= 3.24.0, <3.26.0

Patched versions
3.26.0


Description

Description

The object-destructuring assignment syntax introduced in Twig 3.24.0
generates a call to CoreExtension::getAttribute() with the $sandboxed
argument hardcoded to false, regardless of whether a SandboxExtension
is active. This permanently disables the sandbox's property and
method policy checks for every destructuring expression.

ObjectDestructuringSetBinary::compile() emits:

CoreExtension::getAttribute($this->env, $this->source, ..., \Twig\Template::ANY_CALL, false, false, false, ...);
//                                                                                ^^^^^
//                                                                       sandbox check never runs

Whereas GetAttrExpression::compile() correctly passes $env->hasExtension(SandboxExtension::class).

An attacker with write access to a sandboxed Twig template can read
any public property or invoke any public getter on objects passed
to the template engine, bypassing SecurityPolicy restrictions. The
exploit requires only the {% do %} tag to be in allowedTags, which
is a common configuration.


Resolution

The destructuring compiler now forwards the active sandbox flag to
getAttribute() so property/method allowlists are enforced.


Credits

We would like to thank Anvil Secure in collaboration with Claude
and Anthropic Research for reporting and fixing the issue.


Severity
High

CVE ID
CVE-2026-46639

Weaknesses
Weakness CWE-693 

_____________________________________________________________________

Possible sandbox bypass when using a source policy
High
nicolas-grekas published GHSA-2q52-x2ff-qgfr May 20, 2026

Package
twig/twig (Composer)

Affected versions
2.16.*,>=3.9.0,<3.26.0

Patched versions
3.26.0


Description

Description

When using the sandbox with a SourcePolicyInterface, Twig does not
always apply the sandbox restriction that forbids non-Closure
callbacks for callback-accepting filters.

The issue affects the sort, filter, map, and reduce filters.

In the affected versions, the runtime check that rejects non-Closure
callbacks in sandbox mode does not use the current template Source.
As a result, when the sandbox is enabled through a source policy
instead of being enabled globally, Twig can incorrectly treat the
current execution as non-sandboxed for these callback checks.

This can allow user-controlled templates to pass arbitrary PHP
callables to callback-accepting filters even though the template
is being sandboxed through a source policy.

The issue happens when all these conditions are met:

    The sandbox is not enabled globally;
    A SourcePolicyInterface enables the sandbox for the rendered
template;
    The template uses one of the sort, filter, map, or reduce
filters;
    The callback is not a Closure.


Resolution

The patch makes callback sandbox checks source-aware by propagating
the current template Source to callback-accepting filters and
using it when deciding whether sandbox restrictions apply.


Credits

We would like to thank XavLim and Wade Sparks for reporting the
issue and Fabien Potencier for fixing the issue.


Severity
High
8.8/ 10

CVSS v3 base metrics
Attack vector
Network
Attack complexity
Low
Privileges required
Low
User interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
High
Availability
High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

CVE ID
CVE-2026-24425

Weaknesses
Weakness CWE-693

Credits

    @fabpot fabpot Remediation developer
    @wsparks-vc wsparks-vc Coordinator
    @XavLimSG XavLimSG Finder
    @Vincent550102 Vincent550102 Reporter

_____________________________________________________________________

Sandbox does not protect against resource exhaustion
Moderate
nicolas-grekas published GHSA-923g-j88x-j34q May 20, 2026

Package
twig/twig (Composer)

Affected versions
< 3.26.0

Patched versions
3.26.0


Description

Description

The Twig sandbox prevents untrusted templates from reaching code, data,
methods, or properties they shouldn't. It does not prevent a template
from consuming CPU, memory, or wall-clock time, even under the
strictest allow-list.


Resolution

This is by design: any limit baked into Twig itself would be both
arbitrary and trivial to work around, since there are many ways a
template can burn resources (large ranges, nested loops, large string
operations, recursive macros, expensive filters, deeply nested
includes, and so on). It would also give a false sense of safety.

If you render untrusted templates, you should contain them at the
process level rather than at the template-engine level. The Twig
documentation now describes this explicitly, along with a few
ideas (PHP's memory_limit / max_execution_time, isolated worker
processes, OS-level limits) worth considering depending on context.

See the "Limiting Resource Usage" section of the sandbox
documentation.


Credits

We would like to thank Kai Aizen (Snailsploit) for reporting the
issue.

Severity
Moderate

CVE ID
CVE-2026-46627

Weaknesses
Weakness CWE-400 
_____________________________________________________________________

`{% sandbox %}{% include %}` skips checkSecurity() on cached templates
(incomplete fix for CVE-2024-45411)

Moderate
nicolas-grekas published GHSA-7fxw-r6jv-74c8 May 20, 2026

Package
twig/twig (Composer)

Affected versions
< 3.26.0

Patched versions
3.26.0


Description
Description

The fix for CVE-2024-45411 / GHSA-6j75-5wfj-gh66 added an explicit
$loaded->unwrap()->checkSecurity() call in CoreExtension::include()
so that a template already cached in Environment::$loadedTemplates
is re-checked when included with sandboxed = true.

The deprecated but still functional
{% sandbox %}{% include ... %}{% endsandbox %} tag path was not
updated: it compiles to enableSandbox(); yield from $this->load(...)->unwrap()->yield(...);
disableSandbox(); with no checkSecurity() re-invocation.
If the included template was loaded once outside the sandbox in the same Environment
instance, its constructor (and therefore its compiled checkSecurity() call) already
ran while isSandboxed() was false, so the tags/filters/functions allowlist enforced
by SecurityPolicy::checkSecurity() is never applied.

An attacker who can author the included template gains access to every filter,
function and tag registered in the environment, regardless of the sandbox
policy.


Resolution

The compiled output of {% sandbox %}{% include %} now calls checkSecurity() on the
loaded template, matching the behaviour of CoreExtension::include() with
sandboxed = true.


Credits

We would like to thank Claude Mythos Preview (via Project Glasswing) for reporting
the issue and providing the fix.


Severity
Moderate

CVE ID
CVE-2026-46638

Weaknesses
Weakness CWE-693 
_____________________________________________________________________


`template_from_string()` escapes a SourcePolicy-driven sandbox via
synthesized template name

Moderate
nicolas-grekas published GHSA-24x9-r6q4-q93w May 20, 2026

Package
twig/twig (Composer)

Affected versions
>= 3.9.0, < 3.26.0

Patched versions
3.26.0

Description

Description

When the sandbox is enabled selectively via SourcePolicyInterface (and
not globally), a sandboxed template that is allowed to call
template_from_string and include can render an arbitrary inner template
with no security policy enforcement.

Environment::createTemplate() compiles the inner string under a
synthesized name (__string_template__<hash>), so a name/path-based
SourcePolicy returns false for it, and the inner template's
checkSecurity() becomes a no-op. From a template the integrator
believes is sandboxed, an attacker can use any tag/filter/function
(including constant() to read secrets, or |map("system") to
execute shell commands).


Resolution

This is a configuration trap rather than a code bug: there is no
legitimate use case for exposing template_from_string to untrusted
template authors, and propagating the parent sandbox state through
template_from_string would require invasive changes to
SourcePolicyInterface semantics with their own risks.

Starting with Twig 3.26.0, the documentation and the PHPDoc of
StringLoaderExtension::templateFromString() explicitly warn against
allowing template_from_string in a sandboxed environment (i.e.
listing it in a SecurityPolicy allowed-functions list). Integrators
using a SourcePolicyInterface MUST NOT allow template_from_string
in their allowed functions; the safest option is not to register
StringLoaderExtension at all when a sandbox is in use.


Credits

We would like to thank Claude Mythos Preview (via Project Glasswing)
for reporting the issue.

Severity
Moderate

CVE ID
CVE-2026-46634

Weaknesses
Weakness CWE-693

_____________________________________________________________________


Sandbox property allowlist bypass via the `column` filter
(array_column on objects)

Moderate
nicolas-grekas published GHSA-vcc8-phrv-43wj May 20, 2026

Package
twig/twig (Composer)

Affected versions
< 3.26.0

Patched versions
3.26.0


Description

Description

The column filter passes its input straight to PHP's native array_column().
When the array elements are objects, array_column() reads
$obj->$name (and $obj->$index) directly, including invoking __get/__isset.
Because this property read happens entirely in PHP native code and never
reaches CoreExtension::getAttribute(),
SandboxExtension::checkPropertyAllowed() is never consulted.

An untrusted template author with column in their allowedFilters list can
therefore read any public or magic property of any object reachable in
the render context, regardless of the SecurityPolicy allowedProperties
list. This is a variant of CVE-2024-51755 / GHSA-jjxq-ff2g-95vh that the
ArrayAccess-focused fix did not cover.


Resolution

The column filter now routes object property reads through the
sandbox-aware attribute accessor so the property allowlist is
enforced.


Credits

We would like to thank Claude Mythos Preview (via Project Glasswing)
for reporting the issue and providing the fix.


Severity
Moderate

CVE ID
CVE-2026-46635

Weaknesses
Weakness CWE-863


=========================================================
+ CERT-RENATER        |    tel : 01-53-94-20-44         +
+ 23/25 Rue Daviel    |    fax : 01-53-94-20-41         +
+ 75013 Paris         |   email:cert@support.renater.fr +
=========================================================




