Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Twig Sandbox Bundle Laravel Package

intaro/twig-sandbox-bundle

Symfony bundle integrating Twig's sandbox extension to safely render untrusted templates with configurable security policies, allowed tags, filters, functions, and methods. Ideal for user-supplied templates.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit — poor, and it needs to be surfaced first. This is a Symfony bundle, not a Laravel package. It registers through the Symfony kernel, contributes a DI compiler pass, and builds its allowlist by scanning Doctrine annotations against Symfony's service metadata. Laravel has no bundle/compiler-pass mechanism; the package's entry point is structurally unusable in a Laravel app. v3.4.0 does not change this — the new strict-mode validator is, by name and by placement, a validator of the sandbox configuration, and its natural home is the same compiler pass.

What is conceptually portable is small: the mapping from a per-class annotation to Twig\Sandbox\SecurityPolicy::setAllowedMethods() / setAllowedProperties(), plus now the strict-mode completeness check. That logic is a few hundred lines at most and can be reimplemented against PHP 8 attributes in Laravel far more cheaply than the bundle can be shimmed.

Integration feasibility — medium-low, with a modestly improved risk profile. The underlying capability (Twig sandbox) is core Twig and works fine in Laravel; the bundle is only the configuration layer. A Laravel path exists but requires work:

  • Add Twig via rcrowe/twigbridge (Blade remains the default; Twig is additive).
  • Construct Twig\Sandbox\SecurityPolicy explicitly and wire it into Twig\Extension\SandboxExtension.
  • Replace Doctrine annotation scanning with native PHP 8 attribute reflection over an explicit namespace list.
  • Cache the compiled policy at build time.
  • New in v3.4.0: replicate the strict-mode validation as a build-time gate, so an unannotated public method in a sandboxed namespace fails CI rather than silently widening or silently breaking the policy.

Technical risk — still elevated, but one of the three concerns is now partially addressed. Four concerns:

  1. Security-critical surface with no downstream validation. Twig sandbox is a safety boundary against untrusted template authors. This package has 7 stars, 0 dependents, and a single-maintainer release cadence — nobody has stress-tested its semantics. The score of 0.245 reflects that; the 51.25 opportunity score suggests the problem is real, not that this artifact solves it. v3.4.0 is one PR from one contributor; it is a signal of life, not of hardening. No new dependents, no external review, no test-coverage evidence in the release notes.
  2. Implicit security policy — mitigated upstream, not yet mitigated for us. Annotation-driven allowlists mean the security boundary lives scattered across docblocks/attributes rather than in one auditable config file. A missing or typo'd annotation silently changes the allowlist. Strict mode is a direct response to exactly this failure, which is the most useful thing about the release — it confirms the risk is real and gives us a named behavior to port. But the mitigation lives in a bundle we cannot install, so the benefit accrues to us only if we build it into the shim. Risk unchanged for our stack as of today.
  3. Unknown strict-mode semantics. The release note is a single line with no documentation of what "strict" means, whether it is opt-in or default, and whether it fails the build or emits a warning. If strict is the default, v3.4.0 is behavior-changing for existing users despite a minor version bump; if opt-in, it changes nothing for anyone who doesn't set a flag.
  4. Annotation deprecation. Doctrine annotations are in maintenance mode; if the bundle hasn't fully moved to attributes, the integration inherits a dead-end dependency. This release does not appear to address it.

Key questions to resolve before any commitment:

  • Do we actually render untrusted, user-authored templates? (CMS blocks, customer-provided email templates, low-code/no-code surfaces.) If not, the sandbox is unnecessary and this entire evaluation is moot.
  • What exactly does strict mode enforce, and is it default-on or opt-in? Does it reject unannotated public methods, unannotated classes in a scanned namespace, unknown annotation targets, or all of these? Does it fail the container build or warn?
  • Can the strict-mode validation logic be lifted independently of the DI compiler pass? It is the single most valuable thing in this repo for our purposes; if it's tangled into Symfony service metadata, we reimplement from the intent rather than the code.
  • Does the bundle support PHP 8 attributes, or only docblock annotations? (Unchanged, and now more urgent — strict mode on top of deprecated annotations compounds the dead-end.)
  • Which Twig versions does it pin, and does it track SecurityPolicy API changes across Twig 3.x?
  • Is the policy computed at container compile time and cached — and what invalidates that cache on deploy?
  • Who owns the fork when Twig ships a breaking change and upstream is dormant?

Integration Approach

Stack fit. Laravel + Twig (via twigbridge) + core Twig sandbox. The bundle is not part of a viable Laravel stack; the pattern it encodes is — and v3.4.0 makes that pattern slightly better specified.

Migration path — port the idea, don't install the package.

  1. Define our own #[SandboxAllowed] / #[SandboxAllowedProperty] attributes.
  2. Write a scanner that reflects over a configured set of namespaces and produces [class => [methods], class => [properties]].
  3. Build a SecurityPolicy from that map, bind it as a singleton, and pass it to SandboxExtension with sandboxed: true on the Twig environment.
  4. Cache the compiled policy (Laravel config/route cache or a build artifact), invalidated by a hash of the scanned source tree.
  5. Adopt strict-mode validation as a first-class part of the scanner, not an afterthought: any public method on a class in a sandboxed namespace that lacks an explicit attribute is a build failure. This is the port of PR #27 and it should land with the initial shim, not in a follow-up.

Compatibility notes. Verify the SecurityPolicy API shape against the Twig version in use — the constructor form (__construct(array $tags, array $filters, array $methods, array $properties, $version)) differs from the fluent setters. TwigBridge's Twig environment setup must be extended to register the sandbox extension and set sandboxed mode; confirm TwigBridge exposes enough hook surface for that (it generally does via its extension registration). Pin the bundle's version in our tracking notes only as a reference implementation — we consume its design, not its code.

Sequencing.

  1. Decision gate: confirm the untrusted-template requirement. No requirement, no sandbox.
  2. Spike TwigBridge + a hardcoded, explicit SecurityPolicy array (no attributes yet).
  3. Only if the allowlist exceeds ~50–100 entries does attribute scanning become worth the indirection.
  4. Introduce strict validation in the same PR as the scanner. Deny-by-default is the property that matters, and a scanner without a completeness check reintroduces the implicit-policy risk we are trying to eliminate.
  5. Add a test suite asserting that every non-allowlisted method throws Twig\Sandbox\SecurityError, plus a test that an unannotated method fails the scan.
  6. Add caching and a CI assertion that the committed policy hash matches a fresh scan, to prevent deploy-time drift.

Operational Impact

Maintenance. Treat this as a fork from day one. Zero dependents and 7 stars mean no community backpressure; Twig major upgrades are entirely our problem. Realistic estimate: near-zero ongoing cost for the attribute-scanning shim, but a recurring review cost every Twig upgrade. v3.4.0 slightly improves the outlook — a substantive contribution from a second contributor (@muxx) suggests the project is not abandoned and is receiving security-relevant attention. It does not change the underlying math: one minor release with no documentation is not a support commitment, and we should still assume we own the code path.

Support. MIT, no vendor, no SLA. Escalation is a low-traffic GitHub issue tracker. Acceptable only because the code being replaced is small enough to own outright — which argues for owning it outright. The v3.4.0 release notes are the evidence: a one-line changelog for a behavior called "strict mode" tells you everything about the documentation depth you'd be depending on.

Scaling. Negligible runtime cost if policy construction and strict validation are build-time only. Attribute reflection across the codebase on every request would be a measurable and pointless regression — and strict mode, which inspects more surface, makes an accidental request-time scan costlier. The sandbox itself adds per-render overhead (method call interception), which matters only at high template-render volume.

Failure modes to instrument for:

  • Silent over-permission — missing attribute causes fallback to a permissive default. Upstream now offers strict mode as the countermeasure; we get no benefit unless we port it. Mitigate with explicit deny-by-default, strict scan-time validation, and a test asserting the fallback denies.
  • Strict-mode false confidence — strict validation passes because attributes exist, but the attributes grant more than intended. Completeness is not correctness; the human audit of the allowlist remains mandatory.
  • Cache staleness — policy compiled before a deploy that added methods; sandbox denies legitimate calls in prod but works in dev.
  • Environment divergence — dev scans on the fly, prod uses cache; the two drift without anyone noticing. If strict mode runs only in one environment, divergence gets worse.
  • Compile-time fatal — unparseable attribute or unresolvable class aborts the build. This is desirable; fail loudly at build, never at request time. Confirm the ported validator exits non-zero and names the offending class.
  • Bypass via filter/function surface — methods are only one axis; tags, filters, and properties must be configured with equal rigor. Strict mode must cover all four axes, not just methods.

Ramp-up. Low for a PHP engineer — the concept is a day of work. The strict-mode addition adds perhaps half a day if we implement it from intent; there is no documentation to follow. High for security review: an implicit, distributed allowlist is materially harder to audit than a single explicit config array, and the audit is the whole point of a sandbox. Budget a dedicated security review plus the deny-by-default and strict-validation test suites before this goes anywhere near production.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console