CVE-2026-48806Medium▾ SunlitTwig: Sandbox `__toString()` policy bypass via dynamic mapping keys
▾ Sunlit zone — Low / medium · no exploitation signal
impact 27.5 · likelihood 0.1 · exploitation 0
Need a working PoC? Pro members can cast a request and our team develops one — it lands right here.
Exploit-prediction probability, daily snapshots since Jul 15.
Disclosure to exploitation, from the record and what we observed since indexing it.
Disclosed via GHSA
0.2%
0.2% → 0.4%
This is a residual bypass of CVE-2026-47732 / GHSA-pr2w-4gpj-cpq4 left after the initial fix for unguarded __toString() calls.
In 3.26.0 the sandbox visitor was extended to wrap every child node that its parent will string-coerce at runtime with CheckToStringNode, gated by the new CoercesChildrenToStringInterface. ArrayExpression did not implement the interface for its mapping keys: when a dynamic key expression resolves to a Stringable object, ArrayExpression::compile() emits a raw (string) cast (via StringCastUnary for ContextVariable keys, and no cast at all for richer key expressions). PHP then invokes __toString() directly, without ever calling SandboxExtension::ensureToStringAllowed().
A sandboxed template author can therefore trigger __toString() on any object reachable in the render context by using it as a dynamic mapping key, for example:
{% set arr = {(obj): "value"} %}
Direct output of the same object is correctly blocked, which makes this a clear policy enforcement gap. The reliable demonstrated impact is unauthorised disclosure of data returned by __toString().
ArrayExpression now declares its dynamic mapping keys as string-coercion sites through CoercesChildrenToStringInterface, so the sandbox visitor wraps them with CheckToStringNode and the policy is consulted before PHP coerces the key to a string. The compiler also keeps an explicit (string) cast around the wrapped expression so PHP type errors on non-string keys are preserved.
As a side effect, any expression is now accepted as a dynamic mapping key (not only context variables); this is documented as a new feature on the 3.x branch.
Twig would like to thank El Kharoubi Iosif for reporting the issue and Fabien Potencier for providing the fix.
twig/twig <= 3.26.0Upgrade to a patched release:
twig/twig 3.27.0Connected by shared product, vendor, weakness, or advisory.
CVE-2026-49981HighTwig: Sandbox filter, tag and function allow-list bypass when sandbox state changes between renders for a cached `Template`
CVE-2026-48807MediumTwig: Sandbox `__toString()` policy bypass via `Traversable` in `join` and `replace` filters
CVE-2026-48808MediumTwig: Sandbox property allowlist bypass via the `column` filter under `SourcePolicyInterface`
CVE-2026-48805LowTwig: Sandbox state regression in deprecated internal wrappers in `src/Resources/core.php`
CVE-2026-77251High· 8.3MCP Atlassian is a Model Context Protocol (MCP) server for Atlassian products (Confluence and Jira)
CVE-2026-39452High· 7.3Protection mechanism failure for some Intel(R) Transfer Learning Tool before version v0.7 within Ring 3: User Applications may allow an escalation of privilege