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