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
- Allow the filter: $policy->setAllowedFilters(array_merge($current, [$filter])) or include it in the constructor's $filters array.
- Audit sandboxed templates (e.g. with a template lint) and align the policy with actually used filters.
- Catch SecurityNotAllowedFilterError around load()/render() to surface the offending filter name to users.
- 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
- Enumerate every filter used by sandboxed templates (grep for '|').
- Update setAllowedFilters whenever templates gain new filters.
- Re-run sandbox test suites after policy or template changes.
- Differentiate dev (verbose catch + log) vs prod (deny + placeholder).
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
- Tag " " is not allowed.
- Function " " is not allowed.
- Test " " is not allowed.
- Calling " " method on a " " object is not allowed.
- Calling " " property on a " " object is not allowed.
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)