twigphp/Twig · error · SecurityNotAllowedFilterError

Filter " " is not allowed.

Error message

Filter "%s" is not allowed.

What it means

checkSecurity() throws SecurityNotAllowedFilterError when a template applies a filter (e.g. |upper, |escape) that is not in allowedFilters. Unlike tags/functions, filters have no deprecation grace period: any non-allowlisted filter is rejected immediately.

Solutions

  1. Allow the filter: $policy->setAllowedFilters(array_merge($current, [$filter])) or include it in the constructor's $filters array.
  2. Audit sandboxed templates (e.g. with a template lint) and align the policy with actually used filters.
  3. Catch SecurityNotAllowedFilterError around load()/render() to surface the offending filter name to users.
  4. Re-check the policy after upgrading Twig in case built-in filter usage changed.

Example fix

// before
 $policy = new SecurityPolicy(['for'], [], [], [], []);
 // template uses {{ name|upper }}
// after
 $policy = new SecurityPolicy(['for'], ['upper'], [], [], []);
Defensive patterns

Strategy: try-catch

Validate before calling

if (!in_array($filter, $policy->getAllowedFilters(), true)) {
    // template would throw; fix policy or template first
}

Try / catch

try {
    $html = $sandboxTwig->load($name)->render($ctx);
} catch (\Twig\Sandbox\SecurityNotAllowedFilterError $e) {
    $logger->warning('Sandbox blocked filter', ['filter' => $e->getFilterName()]);
}

Prevention

When it happens

Trigger: A sandboxed template uses a filter not passed to SecurityPolicy's $filters constructor argument nor added via setAllowedFilters(); test fixtures intentionally using banned filters.

Common situations: Adding new template logic that uses a filter the policy never allowed; copying a policy between projects with different filter sets; writing sandbox tests (testStrictMode*, testAllowedTestsCanBeUpdatedViaSetter) that assert rejection.

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/f5fe3f838dcec3b2. Report an issue: GitHub.

Appendix: source

Thrown at src/Sandbox/SecurityPolicy.php:118

        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).');
                } else {
                    throw new SecurityNotAllowedFunctionError(\sprintf('Function "%s" is not allowed.', $function), $function);
                }
            }
        }

        foreach ($tests as $test) {

View on GitHub (pinned to a414c3a491)