CVE-2026-47732 - Twig toString sandbox bypass
Twig versions through 3.25.0 can miss sandbox checks before PHP implicitly
coerces Stringable objects to strings. A sandboxed template author can reach
__toString() on objects available in the render context even when that method
is not allow-listed by the Twig security policy.
This matters most in products that expose Twig templates to tenants, CMS users, theme authors, support staff, marketing teams, plugin authors, or automation workflows. A simple package bump is not enough for reviewer confidence: the PR should also show which objects are reachable from sandboxed templates and how compiled template caches/workers are handled.
When to use it
Use this recipe when a PHP repository renders sandboxed Twig templates that can
be authored or influenced by tenants, CMS editors, theme authors, support
staff, marketing users, plugin authors, automation, or agents. It is most
valuable when template contexts include Stringable domain objects, request
wrappers, service objects, lazy proxies, URL objects, or other objects whose
__toString() may reveal data or trigger side effects.
Use it to upgrade Twig, narrow sandbox contexts, and plan cache/worker cleanup. Do not use it to run bypass payloads or leak values through string oracles.
Inputs
composer.json,composer.lock, framework integrations, Dockerfiles, deployment manifests, CI images, generated dependency reports, SBOMs, template loaders, sandbox policies, compiled caches, and local forks.- Sandboxed render paths and policies:
SandboxExtension,SecurityPolicy,createTemplate, template preview/edit flows, CMS/theme/email/report features, and user-template storage. - Template-author groups and trust levels: developers, admins, support, CMS editors, tenants, plugin authors, automation accounts, unauthenticated users, and imported third-party templates.
- Context object inventory for
Stringable,__toString, request/session, service, filesystem, URL signer, HTTP client, database, model, lazy proxy, and secret-bearing objects. - Deployment cleanup requirements for compiled Twig caches, warmed layouts, PHP-FPM, RoadRunner, FrankenPHP, Messenger workers, queues, and hot workers.
Affected versions
- Vulnerable package:
twig/twig <=3.25.0 - Fixed package:
twig/twig 3.26.0+ - Preferred target:
twig/twig 3.27.0+because CVE-2026-48806 and CVE-2026-48807 were residual__toString()sandbox bypasses fixed after3.26.0. - Affected surfaces: sandboxed templates with access to
Stringableobjects and Twig constructs that coerce values to strings. - Required attacker capability: ability to author or influence sandboxed Twig template source.
Indicator-of-exposure
- The repository depends on
twig/twig <=3.25.0. - The application renders untrusted or semi-trusted Twig source under
SandboxExtensionorSecurityPolicy. - Template contexts include
Stringabledomain objects, value objects, user records, URLs, request/session wrappers, service objects, model objects, or lazy proxies. - Template authors can use conditionals,
matches, loose comparisons, tests, null-coalescing, concatenation, functions, filters, method arguments, dynamic attribute names,include,extends,use,do, ranges, spread arguments,join,replace, orin/not in. - Reviewers cannot tell from the current code which template authors are trusted and which context objects are intentionally exposed.
Quick checks:
rg -n "twig/twig|SandboxExtension|SecurityPolicy|Stringable|__toString|matches|is empty|include|extends|use|join\(|replace\(|not in|createTemplate|template|theme|cms|email" .
composer show twig/twig
composer why twig/twig
rg -n "SandboxExtension|SecurityPolicy|Stringable|__toString|twig/twig|createTemplate|join\(|replace\(" composer.json composer.lock config src templates app resources tests . 2>/dev/null
Windows:
rg -n "twig/twig|SandboxExtension|SecurityPolicy|Stringable|__toString|matches|is empty|include|extends|use|join\(|replace\(|not in|createTemplate|template|theme|cms|email" .
composer show twig/twig
composer why twig/twig
rg -n "SandboxExtension|SecurityPolicy|Stringable|__toString|twig/twig|createTemplate|join\(|replace\(" composer.json composer.lock config src templates app resources tests .
Do not run bypass payloads, leak values through string-comparison oracles, dump template contexts, or render production templates during triage.
Remediation strategy
- Upgrade every controlled
twig/twigpackage, lockfile, image, SBOM, generated dependency report, and deployment artifact to3.26.0+. - Prefer
3.27.0+so the deployment receives the May 27 residual__toString()sandbox fixes for dynamic mapping keys and traversable coercion paths. - Clear compiled Twig caches and restart long-lived PHP workers after upgrade.
- Inventory sandboxed template contexts and remove broad objects from untrusted templates. Pass scalar or narrow DTO/view-model fields where possible.
- Add regression tests that verify dependency policy and benign sandboxed
rendering with
Stringableobjects, without executing exploit payloads or leaking sensitive values. - If upgrade is blocked, disable untrusted template editing/rendering or remove
Stringableand privileged objects from untrusted contexts until the fixed Twig release can deploy.
The prompt
You are remediating CVE-2026-47732 / GHSA-pr2w-4gpj-cpq4, a Twig sandbox
bypass where incomplete string-coercion checks can invoke disallowed
`__toString()` methods on objects reachable from sandboxed templates. Produce
exactly one output:
- A reviewer-ready PR/change request that upgrades Twig, audits sandboxed
template contexts, clears compiled caches/workers, adds safe regression
coverage, refreshes generated artifacts, and documents operator cleanup, or
- TRIAGE.md if this repository does not control an affected Twig runtime or any
sandboxed user-controlled template source.
## Rules
- Scope only CVE-2026-47732 / GHSA-pr2w-4gpj-cpq4 and directly related Twig
sandbox, `Stringable`, template context, cache, and deployment controls.
- Treat template source, template contexts, rendered content, `Stringable`
values, users, orders, customer data, request/session objects, URLs, tokens,
secrets, logs, and compiled template caches as sensitive.
- Do not run bypass payloads, create string-comparison oracles, render attacker
templates, dump context objects, mutate live templates, or print secret-like
values.
- Do not remove sandboxing, authorization, audit logging, template review, cache
isolation, or tests to silence the advisory.
- Do not auto-merge.
## Steps
1. Inventory all Twig usage controlled by the repository: `composer.json`,
`composer.lock`, framework integrations, Dockerfiles, deployment manifests,
CI images, generated dependency reports, SBOMs, template loaders, sandbox
policies, user-template features, compiled template caches, and local forks.
2. Determine every resolved `twig/twig` version. A target is vulnerable if it
resolves to `<=3.25.0`.
3. Search for sandboxed template rendering and string-coercion exposure:
`SandboxExtension`, `SecurityPolicy`, `Stringable`, `__toString`,
`createTemplate`, CMS/theme/email/report/template-preview features,
conditionals, `matches`, comparisons, `is empty`, null coalescing,
concatenation, dynamic attributes, spread arguments, `include`, `extends`,
`use`, `do`, ranges, `join`, `replace`, `in`, and `not in`.
4. Classify every template-author group: trusted developers, admins, support
staff, tenants, CMS editors, theme authors, plugin authors, automation
accounts, unauthenticated users, or imported third-party templates.
5. If Twig is absent, fixed, or used only for trusted developer-authored
templates, stop with `TRIAGE.md` listing checked files, resolved version,
and exposure rationale.
6. Upgrade all controlled Twig dependencies to `3.26.0+`; prefer `3.27.0+`
unless compatibility testing requires the smaller fixed target. Refresh
lockfiles, images, deployment artifacts, generated dependency reports, SBOMs,
and docs that pin Twig.
7. Clear compiled templates and restart long-lived workers:
- remove Twig cache directories during deploy;
- rebuild images or release artifacts that contain compiled templates;
- restart PHP-FPM pools, RoadRunner, FrankenPHP, Messenger workers, queues,
and other hot worker processes;
- document any operator-owned cache paths outside the repository.
8. Audit and harden sandboxed template contexts:
- replace rich domain objects with scalar DTO/view-model fields;
- remove service containers, database clients, request/session wrappers,
filesystem clients, URL signers, HTTP clients, and secret-bearing objects;
- document every remaining `Stringable` object exposed to untrusted
templates and why it is safe;
- verify template editing/preview endpoints require authorization and audit.
9. Add safe regression coverage:
- dependency policy rejects `twig/twig <=3.25.0`;
- benign sandboxed templates render after upgrade;
- a fixture `Stringable` object whose `__toString()` is not allow-listed is
rejected without leaking the returned value;
- logs and test output do not contain sensitive context data.
10. Add a PR body section named `CVE-2026-47732 operator actions` that states:
- Twig versions before and after;
- which sandboxed template surfaces exist;
- which template author groups can edit or preview templates;
- what context objects were removed or narrowed;
- which compiled caches and workers must be cleared/restarted;
- whether CVE-2026-48806 and CVE-2026-48807 residual fixes are covered by
the chosen Twig version;
- whether audit review, template rollback, or secret rotation is needed;
- which validation commands passed.
11. Run available validation: Composer install/check-platform-reqs, lockfile
integrity, unit/feature tests, benign sandbox rendering tests, static
analysis, lint, deployment rendering, image build, SBOM refresh, and
dependency/security scans.
12. Use PR title:
`fix(sec): remediate CVE-2026-47732 in Twig sandboxing`.
## Stop conditions
- No affected Twig package, sandboxed template renderer, user-controlled
template source, compiled cache, or deployment artifact is controlled by this
repository.
- The Twig runtime or template subsystem is owned by another team; name the
owner and required fixed version in `TRIAGE.md`.
- Upgrading Twig requires a broader PHP/framework migration or maintenance
window the agent cannot schedule.
- Verification would require running bypass payloads, leaking values through
string oracles, dumping template contexts, mutating live templates, or
exposing secrets.
- Validation fails for unrelated pre-existing reasons; document those failures
instead of broadening scope.
Verification - what the reviewer looks for
- No controlled Composer lockfile, package manifest, image, SBOM, or generated
dependency report resolves
twig/twig <=3.25.0. - The selected fixed version also accounts for CVE-2026-48806 and CVE-2026-48807 when the application exposes untrusted sandboxed templates.
- Sandboxed template contexts are inventoried and do not expose broad secret-bearing objects to untrusted authors.
- Compiled Twig caches and long-lived workers are cleared or explicitly covered in operator notes.
- Regression tests prove safe rejection without rendering bypass payloads or
leaking
__toString()output.
Watch for
- Stopping at
3.26.0while the application exposes the residual__toString()coercion surfaces fixed in3.27.0. - Treating sandboxed template authors as trusted because they are authenticated admins, tenants, or CMS editors.
- Leaving rich domain objects in context because committed templates currently use them.
- Forgetting compiled template caches, warmed layouts, includes, macro imports, or long-lived workers.
- Tests that render committed templates only and never exercise the sandboxed user-template path.
Output contract
Return one of:
- A reviewer-ready PR/change request that upgrades
twig/twigto3.26.0+or preferably3.27.0+, audits sandboxed template contexts, removes or narrows riskyStringableobjects, clears compiled caches/workers, adds safe regression coverage, refreshes generated artifacts, and documents operator cleanup. TRIAGE.mdwhen no controlled affected Twig runtime, sandboxed user-controlled template source, compiled cache, or deployment artifact exists.
The output must list versions before/after, sandboxed surfaces, author groups,
context objects removed or retained, chosen Twig version coverage for residual
fixes, cache/worker actions, validation commands, and whether audit review,
template rollback, or secret rotation is needed. It must not render bypass
payloads, dump contexts, mutate live templates, leak __toString() values, or
print sensitive rendered content.
Related recipes
- CVE-2026-46640 - Twig macro-reference compilation RCE
- CVE-2026-46636 - Twig cached template sandbox state bypass
- Source-code injection sink audit
References
- GitHub Advisory Database: https://github.com/advisories/GHSA-pr2w-4gpj-cpq4
- Twig advisory: https://github.com/twigphp/Twig/security/advisories/GHSA-pr2w-4gpj-cpq4
- Symfony advisory: https://symfony.com/cve-2026-47732
- CVE-2026-48806 residual fix: https://symfony.com/blog/cve-2026-48806-sandbox-tostring-policy-bypass-via-dynamic-mapping-keys
- CVE-2026-48807 residual fix: https://symfony.com/blog/cve-2026-48807-sandbox-tostring-policy-bypass-via-traversable-in-join-replace-and-in-not-in-operators
- Twig 3.26.0 release: https://github.com/twigphp/Twig/releases/tag/v3.26.0
- Twig 3.27.0 release: https://github.com/twigphp/Twig/releases/tag/v3.27.0