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 after 3.26.0.
  • Affected surfaces: sandboxed templates with access to Stringable objects 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 SandboxExtension or SecurityPolicy.
  • Template contexts include Stringable domain 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, or in / 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/twig package, lockfile, image, SBOM, generated dependency report, and deployment artifact to 3.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 Stringable objects, without executing exploit payloads or leaking sensitive values.
  • If upgrade is blocked, disable untrusted template editing/rendering or remove Stringable and 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.0 while the application exposes the residual __toString() coercion surfaces fixed in 3.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/twig to 3.26.0+ or preferably 3.27.0+, audits sandboxed template contexts, removes or narrows risky Stringable objects, clears compiled caches/workers, adds safe regression coverage, refreshes generated artifacts, and documents operator cleanup.
  • TRIAGE.md when 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.

References