twigphp/Twig · error · SecurityNotAllowedTagError

Tag " " is not allowed.

Error message

Tag "%s" is not allowed.

What it means

The sandbox SecurityPolicy throws SecurityNotAllowedTagError during checkSecurity() when a Twig tag used in the template is not in the allowedTags list. With strict mode off, 'extends' and 'use' are still permitted with a deprecation notice; everything else unlisted is rejected.

Solutions

  1. Add the required tag to the policy: new SecurityPolicy($tags, ...) or $policy->setAllowedTags([...]) including 'extends'/'use' explicitly.
  2. Enable strict mode ($policy->setStrict(true)) in development to surface all future 4.0 rejections now and fix the allowlist.
  3. Restructure the sandboxed template to avoid the disallowed tag.
  4. Handle SecurityNotAllowedTagError in the rendering wrapper to report which tag was blocked.

Example fix

// before
 $policy = new SecurityPolicy([], [], [], [], []); // no tags allowed
// after
 $policy = new SecurityPolicy(['if', 'for', 'extends', 'use'], [], [], [], []);
 $policy->setStrict(true);
Defensive patterns

Strategy: try-catch

Validate before calling

$usedTags = extractTemplateTags($templateSource); // your own static scan
$missing = array_diff($usedTags, $allowedTags);
if ($missing) { /* adjust policy before rendering */ }

Try / catch

try {
    $html = $twig->render($sandboxedTemplate, $data);
} catch (\Twig\Sandbox\SecurityNotAllowedTagError $e) {
    $logger->warning('Sandbox blocked tag', ['tag' => $e->getTagName()]);
    $html = '';
}

Prevention

When it happens

Trigger: Rendering a template inside {% sandbox %} (or via SandboxExtension) whose policy allowlist omits a tag the template uses (e.g. 'if', 'for', 'include' not passed to the SecurityPolicy constructor or setAllowedTags()).

Common situations: Tightening a sandbox policy for Twig 4.0 compatibility (tags like extends/use/parent/block/attribute will no longer be implicitly allowed); new template code using a tag the policy author never allowlisted.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of twigphp/Twig@a414c3a491 (2026-09-13). Data as JSON: /api/errors/90898387607287a8. Report an issue: GitHub.

Appendix: source

Thrown at src/Sandbox/SecurityPolicy.php:111

    public function isStrict(): bool
    {
        return $this->strict;
    }

    public function checkSecurity($tags, $filters, $functions, array $tests = []): void
    {
        if (\func_num_args() < 4) {
            trigger_deprecation('twig/twig', '3.28', 'Not passing the "$tests" argument to "%s::checkSecurity()" is deprecated; it will be required in 4.0.', static::class);
        }

        foreach ($tags as $tag) {
            if (!\in_array($tag, $this->allowedTags, true)) {
                if (!$this->strict && 'extends' === $tag) {
                    trigger_deprecation('twig/twig', '3.12', 'The "extends" tag is always allowed in sandboxes, but won\'t be in 4.0, please enable it explicitly in your sandbox policy if needed (or enable strict mode on the security policy to opt-in to the 4.0 behavior now).');
                } elseif (!$this->strict && 'use' === $tag) {
                    trigger_deprecation('twig/twig', '3.12', 'The "use" tag is always allowed in sandboxes, but won\'t be in 4.0, please enable it explicitly in your sandbox policy if needed (or enable strict mode on the security policy to opt-in to the 4.0 behavior now).');
                } else {
                    throw new SecurityNotAllowedTagError(\sprintf('Tag "%s" is not allowed.', $tag), $tag);
                }
            }
        }

        foreach ($filters as $filter) {
            if (!\in_array($filter, $this->allowedFilters, true)) {
                throw new SecurityNotAllowedFilterError(\sprintf('Filter "%s" is not allowed.', $filter), $filter);
            }
        }

        foreach ($functions as $function) {
            if (!\in_array($function, $this->allowedFunctions, true)) {
                if (!$this->strict && 'parent' === $function) {
                    trigger_deprecation('twig/twig', '3.27', 'The "parent" function is always allowed in sandboxes, but won\'t be in 4.0, please enable it explicitly in your sandbox policy if needed (or enable strict mode on the security policy to opt-in to the 4.0 behavior now).');
                } elseif (!$this->strict && 'block' === $function) {
                    trigger_deprecation('twig/twig', '3.27', 'The "block" function is always allowed in sandboxes, but won\'t be in 4.0, please enable it explicitly in your sandbox policy if needed (or enable strict mode on the security policy to opt-in to the 4.0 behavior now).');
                } elseif (!$this->strict && 'attribute' === $function) {
                    trigger_deprecation('twig/twig', '3.27', 'The "attribute" function is always allowed in sandboxes, but won\'t be in 4.0, please enable it explicitly in your sandbox policy if needed (or enable strict mode on the security policy to opt-in to the 4.0 behavior now).');

View on GitHub (pinned to a414c3a491)