Affected versions

Twig versions <=3.26.0 are affected by this security issue.

The issue has been fixed in Twig 3.27.0.

Description

The 3.26.0 source-policy hardening changed the signature of CoreExtension::checkArrow() to take a boolean $isSandboxed instead of an Environment, and added the same $isSandboxed argument to CoreExtension::arraySome() and CoreExtension::arrayEvery(). Compiled templates were updated to pass the per-source sandbox state computed at the call site.

The deprecated internal wrappers exposed in src/Resources/core.php for legacy third-party code (twig_check_arrow_in_sandbox(), twig_array_some(), twig_array_every()) were not updated:

  • twig_array_some() and twig_array_every() call CoreExtension::arraySome() / arrayEvery() without forwarding the sandbox state. The underlying methods default $isSandboxed to false, so the callable-must-be-a-Closure restriction is silently bypassed in sandbox mode and a string callable such as 'strcmp' is accepted.
  • twig_check_arrow_in_sandbox() passes the Environment object where CoreExtension::checkArrow() now expects a bool, which throws a TypeError on PHP 8+.

Compiled Twig templates are not affected: they call CoreExtension::* directly with the correct arguments. Applications are only impacted if they still call the deprecated twig_* helpers on top of a sandboxed Environment.

Resolution

The three wrappers now resolve the current sandbox state via twig_resolve_is_sandboxed() (the same helper compiled templates use), and forward it to the corresponding CoreExtension::* method. twig_check_arrow_in_sandbox() no longer triggers a TypeError, and twig_array_some() / twig_array_every() now enforce the same sandbox restriction as compiled templates.

Credits

We would like to thank El Kharoubi Iosif for reporting the issue and Fabien Potencier for providing the fix.