getgrav/grav · error · SecurityNotAllowedTestError

Test "%s" is not allowed.

Error message

Test "%s" is not allowed.

What it means

GravSecurityPolicy::checkSecurity() enforces the sandbox allowlists Twig asks about before executing a template body; this branch covers Twig tests (the `is` operator, e.g. `x is iterable`). Grav ships with allowedTests = null, leaving tests unrestricted to match pre-3.28 Twig behavior, but any policy constructed with a concrete list (Twig 3.28 added the $tests argument, required from Twig 4.0) throws SecurityNotAllowedTestError for every test not on it.

Source

Thrown at system/src/Grav/Common/Twig/Sandbox/GravSecurityPolicy.php:58

        private array $allowedMethods = [],
        private array $allowedProperties = [],
        private array $allowedFunctions = [],
        private ?array $allowedTests = null,
    ) {
    }

    /**
     * Twig 3.28 added the `$tests` argument, required from Twig 4.0.
     *
     * Grav has no allowlist for tests yet, so the default is to leave them unrestricted, which is
     * what the sandbox did before 3.28. Pass `$allowedTests` to the constructor to start enforcing.
     */
    public function checkSecurity($tags, $filters, $functions, array $tests = []): void
    {
        if (null !== $this->allowedTests) {
            foreach ($tests as $test) {
                if (!in_array($test, $this->allowedTests, true)) {
                    throw new SecurityNotAllowedTestError(sprintf('Test "%s" is not allowed.', $test), $test);
                }
            }
        }

        foreach ($tags as $tag) {
            if (!in_array($tag, $this->allowedTags, true)) {
                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)) {

View on GitHub (pinned to 6040efed04)

Solutions

  1. Add the test name to the allowlist when the policy is constructed (the security.twig_content configuration / Security::buildTwigSandboxPolicy)
  2. Replace the test with an allowed construct in sandboxed content (e.g. use a filter or explicit comparison that is already permitted)
  3. Move the logic into an unsandboxed theme template or plugin if the test is essential

Example fix

// before: policy enforces tests but omits 'iterable'
new GravSecurityPolicy($tags, $filters, $methods, $props, $functions, ['constant', 'defined']);

// after: allowlist the tests sandboxed content needs
new GravSecurityPolicy($tags, $filters, $methods, $props, $functions, ['constant', 'defined', 'iterable', 'odd']);
Defensive patterns

Strategy: try-catch

Validate before calling

// before rendering sandboxed content with a policy that enforces tests
$testsUsed = ['iterable', 'odd']; // extracted from the template
$allowed = $policyTests ?? [];
$disallowed = array_diff($testsUsed, $allowed);
if ($disallowed) { // fix the template or extend the allowlist before render
    throw new InvalidArgumentException('Tests not allowed in sandbox: ' . implode(',', $disallowed));
}

Try / catch

use Twig\Sandbox\SecurityNotAllowedTestError;
try { echo $twig->render($sandboxedTemplate, $data); }
catch (SecurityNotAllowedTestError $e) { log_refused_test($e->getTestName()); echo '<!-- test refused by sandbox -->'; }

Prevention

When it happens

Trigger: Sandboxed content using {{ x is iterable }}, {{ n is odd }}, or a custom test while the GravSecurityPolicy was built with an allowedTests list that omits it; enabling stricter security.twig_content settings that start enforcing tests; preparing for Twig 4 by passing an explicit test allowlist.

Common situations: Tightening sandbox configuration after a security review; Grav/Twig upgrades where previously-unchecked tests become checked; plugin-provided tests used inside sandboxed page content.

Related errors


AI-assisted analysis of getgrav/grav@6040efed04 (2026-08-17). Data as JSON: /api/errors/ddc81b7a8951cd6c. Report an issue: GitHub.