twigphp/Twig · error · SecurityNotAllowedTestError

Test " " is not allowed.

Error message

Test "%s" is not allowed.

What it means

checkSecurity() throws SecurityNotAllowedTestError when a template uses a Twig test (e.g. is odd, is defined) not in allowedTests. Before strict mode, unlisted tests only trigger a deprecation (they were historically always allowed in sandboxes); with strict mode enabled they throw immediately, matching planned 4.0 behavior.

Solutions

  1. Add the required tests to the policy: $policy->setAllowedTests([...]) or the constructor's $tests argument.
  2. Catch SecurityNotAllowedTestError around sandboxed rendering to identify the blocked test.
  3. Explicitly enumerate every test used by sandboxed templates when strict mode is on.
  4. Keep strict mode enabled in CI so missing test allowlist entries fail tests, not production.

Example fix

// before
 $policy->setStrict(true); // template: {% if n is odd %}
// after
 $policy->setAllowedTests(['odd', 'even', 'defined']);
 $policy->setStrict(true);
Defensive patterns

Strategy: try-catch

Validate before calling

foreach ($testsUsed as $t) {
    if (!in_array($t, $allowedTests, true)) { /* update setAllowedTests */ }
}

Try / catch

try {
    $html = $twig->render($tpl, $ctx);
} catch (\Twig\Sandbox\SecurityNotAllowedTestError $e) {
    $logger->warning('Sandbox blocked test', ['test' => $e->getTestName()]);
}

Prevention

When it happens

Trigger: checkSecurity() called with $this->strict = true and a test absent from allowedTests (as exercised by testStrictModeCanBeEnabledViaSetterAfterConstruction, testStrictModeRejectsTestsViaSetter, testAllowedTestsCanBeUpdatedViaSetter); enabling strict mode via setStrict(true) then rendering a template that uses tests.

Common situations: Testing the Twig 3.28 deprecation/strict-mode transition for sandboxed tests; hardening a sandbox ahead of 4.0 where tests must be explicitly allowed.

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

Appendix: source

Thrown at src/Sandbox/SecurityPolicy.php:141

            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) {
            if (!\in_array($test, $this->allowedTests, true)) {
                if (!$this->strict) {
                    trigger_deprecation('twig/twig', '3.28', 'The "%s" test 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).', $test);
                } else {
                    throw new SecurityNotAllowedTestError(\sprintf('Test "%s" is not allowed.', $test), $test);
                }
            }
        }
    }

    public function checkMethodAllowed($obj, $method): void
    {
        if ($obj instanceof Template || $obj instanceof Markup) {
            return;
        }

        $allowed = false;
        $method = strtolower($method);
        foreach ($this->allowedMethods as $class => $methods) {
            if ($obj instanceof $class && \in_array($method, $methods, true)) {
                $allowed = true;
                break;
            }

View on GitHub (pinned to a414c3a491)