Affected versions
Twig versions >=3.15.0, <3.26.0 are affected by this security issue.
The issue has been fixed in Twig 3.26.0.
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.