Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-46638

CVE-2026-46638: Symfony Twig Privilege Escalation Flaw

CVE-2026-46638 is a privilege escalation vulnerability in Symfony Twig that allows sandbox bypass through cached templates. This article covers the technical details, affected versions, security impact, and mitigation.

Published:

CVE-2026-46638 Overview

CVE-2026-46638 is a sandbox bypass vulnerability in Twig, the template language for PHP maintained by the Symfony project. Versions prior to 3.26.0 allow the {% sandbox %}{% include %} construct to reuse a template that was previously loaded outside the sandbox context. When this occurs, Twig does not re-invoke checkSecurity() on the cached template. As a result, the included template can execute tags, filters, and functions that SecurityPolicy::checkSecurity() would otherwise deny. The issue is fixed in Twig 3.26.0.

Critical Impact

Authenticated template authors can bypass the Twig SecurityPolicy and invoke denied tags, filters, and functions, undermining the isolation guarantees of the {% sandbox %} tag.

Affected Products

  • Symfony Twig versions prior to 3.26.0
  • PHP applications embedding Twig with the SecurityPolicy sandbox
  • Downstream frameworks and CMS platforms bundling vulnerable Twig releases

Discovery Timeline

  • 2026-07-14 - CVE-2026-46638 published to NVD
  • 2026-07-16 - Last updated in NVD database

Technical Details for CVE-2026-46638

Vulnerability Analysis

Twig's sandbox mode enforces a SecurityPolicy that restricts which tags, filters, and functions untrusted templates may use. The policy is applied through checkSecurity() when a template is loaded inside a {% sandbox %} block. This CVE is classified under [CWE-693] Protection Mechanism Failure.

The flaw arises when the same template is first loaded outside the sandbox and later reused via {% sandbox %}{% include 'template.twig' %}. Twig caches compiled templates for performance. On the second inclusion, the cached instance is returned without the sandbox marking, so the SecurityPolicy checks are skipped. The included template therefore executes with the full Twig capability set instead of the restricted sandbox surface.

Root Cause

The root cause lies in IncludeNode and SandboxTokenParser. The sandbox token parser did not propagate a sandboxed attribute to the underlying IncludeNode, so the compiled include code did not enable sandbox mode for the child template. When the child template was already present in Twig's runtime cache from a prior non-sandboxed load, the security policy was never consulted.

Attack Vector

An attacker who can author or influence Twig templates rendered by the application can craft a template that first loads a target template outside a sandbox block, then re-includes it inside {% sandbox %}. The second include reuses the cached template and runs denied constructs. Exploitation requires the ability to submit templates or control template composition, which typically maps to a low-privileged authenticated user in CMS or SaaS scenarios that expose Twig templating to tenants.

php
// Patch excerpt: src/Node/IncludeNode.php
{
    $compiler->addDebugInfo($this);

    $sandboxed = $this->hasAttribute('sandboxed') && $this->getAttribute('sandboxed');

    if ($this->getAttribute('ignore_missing')) {
        $template = $compiler->getVarName();
// Source: https://github.com/twigphp/Twig/commit/819c6a89fe0f261b8555c4f4d5e27d31984223ea
php
// Patch excerpt: src/TokenParser/SandboxTokenParser.php
$stream->expect(Token::BLOCK_END_TYPE);

// in a sandbox tag, only include tags are allowed
if ($body instanceof IncludeNode) {
    $body->setAttribute('sandboxed', true);
} else {
    foreach ($body as $node) {
        if ($node instanceof TextNode && ctype_space($node->getAttribute('data'))) {
            continue;
// Source: https://github.com/twigphp/Twig/commit/819c6a89fe0f261b8555c4f4d5e27d31984223ea

The patch marks the IncludeNode inside a {% sandbox %} tag with a sandboxed attribute so the compiled include forces the SecurityPolicy check even when the template is already cached.

Detection Methods for CVE-2026-46638

Indicators of Compromise

  • Twig templates containing {% sandbox %}{% include %} sequences that reference templates also included elsewhere without a sandbox block.
  • Application logs showing execution of Twig tags, filters, or functions that the configured SecurityPolicy should have blocked.
  • Unexpected calls to PHP functions or filesystem access originating from Twig render paths handling user-supplied templates.

Detection Strategies

  • Inventory installed Twig versions across PHP application stacks and flag any release prior to 3.26.0.
  • Perform static analysis of template repositories to identify templates that are loaded both inside and outside of {% sandbox %} blocks.
  • Instrument the SecurityPolicy::checkSecurity() path with logging to record which template names actually trigger a policy evaluation.

Monitoring Recommendations

  • Enable audit logging on user-submitted template content and on Twig cache regeneration events.
  • Alert on PHP-FPM or web worker processes spawning unexpected child processes or performing outbound requests from Twig render contexts.
  • Track dependency manifests (composer.lock) in CI to detect the presence of pinned vulnerable Twig versions.

How to Mitigate CVE-2026-46638

Immediate Actions Required

  • Upgrade Twig to version 3.26.0 or later in all PHP applications using the {% sandbox %} tag.
  • Audit template sources for tenants or users who can author Twig markup and revoke access where feasible until patching completes.
  • Purge the compiled Twig template cache after upgrading so newly compiled templates carry the corrected sandbox attribute.

Patch Information

The fix is delivered in Twig 3.26.0. The corrective change is in commit 819c6a89fe0f261b8555c4f4d5e27d31984223ea, and full details are published in GitHub Security Advisory GHSA-7fxw-r6jv-74c8. The patch sets a sandboxed attribute on IncludeNode when the include is compiled inside a {% sandbox %} block, forcing checkSecurity() on the included template.

Workarounds

  • Disable or remove use of the {% sandbox %} tag until the Twig library can be upgraded.
  • Ensure any template loaded inside a sandbox is not also loaded outside of one, eliminating the cached-instance reuse condition.
  • Restrict template authoring privileges to trusted operators only, reducing exposure to attacker-controlled Twig source.
bash
# Upgrade Twig to the patched release via Composer
composer require "twig/twig:^3.26.0"
composer update twig/twig

# Clear compiled template cache after upgrade
rm -rf var/cache/*/twig

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.