getgrav/grav · error · SecurityNotAllowedFilterError

Filter "%s" is not allowed on a "%s" object inside sandboxed

Error message

Filter "%s" is not allowed on a "%s" object inside sandboxed content.

What it means

Same dump-guard family as the nesting limit: when the value passed to a guarded filter (print_r, vardump, yaml_encode, json_encode, string) in sandboxed content is an object, its class must be explicitly allowed. Reflective filters (print_r, vardump) accept only stdClass; policy filters (yaml_encode, json_encode, string) require GravSecurityPolicy::isClassAllowed() to be true, i.e. the class appears in the sandbox's allowedMethods map. Serializing anything else would bypass the sandbox's member gate by dumping PHP object state directly (GHSA-mc5q-6hpj-rp7j).

Source

Thrown at system/src/Grav/Common/Twig/Extension/GravExtension.php:395

        }

        if (is_array($var)) {
            foreach ($var as $item) {
                $this->scanSandboxDump($policy, $item, $filter, $reflective, $depth + 1);
            }
            return;
        }

        if (!is_object($var)) {
            return;
        }

        $allowed = $reflective
            ? $var instanceof \stdClass
            : ($policy !== null && $policy->isClassAllowed($var));

        if (!$allowed) {
            throw new SecurityNotAllowedFilterError(
                sprintf('Filter "%s" is not allowed on a "%s" object inside sandboxed content.', $filter, $var::class),
                $filter
            );
        }
    }

    /**
     * @param Environment $env
     * @param mixed $var
     * @return string
     */
    public function printRGuarded(Environment $env, mixed $var)
    {
        $this->assertSandboxDumpSafe($env, $var, 'print_r', true);
        return $this->print_r($var);
    }

    /**

View on GitHub (pinned to 6040efed04)

Solutions

  1. Serialize plain arrays/scalars instead of objects: {{ page.header|print_r }} (array) rather than {{ page|print_r }} (Page object)
  2. Move the debug/serialization into an unsandboxed theme template or a plugin
  3. If the object must be exposed, add its class to the sandbox policy allowedMethods via the security.twig_content configuration — weigh this carefully, it widens the sandbox
  4. For config access, use the provided SandboxConfig facade rather than raw Config/Data objects

Example fix

{# before (sandboxed content): Page object is refused #}
{{ page|print_r }}

{# after: plain array header data passes #}
{{ page.header|print_r }}
Defensive patterns

Strategy: type-guard

Validate before calling

// only pass values the sandbox will serialize
if (is_object($value) && !$value instanceof stdClass && !$policy->isClassAllowed($value)) {
    $value = is_callable([$value, 'toArray']) ? $value->toArray() : (array) $value; // or render a placeholder
}

Type guard

function isSandboxSerializable(mixed $v, ?GravSecurityPolicy $policy, bool $reflective): bool
{
    if (!is_object($v)) { return true; }
    return $reflective ? $v instanceof \stdClass : ($policy !== null && $policy->isClassAllowed($v));
}

Try / catch

use Twig\Sandbox\SecurityNotAllowedFilterError;
try { echo $twig->render($sandboxedTemplate, $data); }
catch (SecurityNotAllowedFilterError $e) { log_refused_class($e->getFilterName()); echo '<!-- object dump refused by sandbox -->'; }

Prevention

When it happens

Trigger: {{ page|print_r }} or {{ grav.page|json_encode }} in sandboxed content where Page is not in the policy allowlist; piping raw Config/Data objects when security.twig_content.config_access is off (only the redacting SandboxConfig facade stays allowed); dumping any service object from markdown-rendered Twig.

Common situations: Theme snippets pasted into page content (sandboxed) that worked in theme templates (not sandboxed); attempts to inspect Grav services from sandboxed markdown; sites updated to a Grav version that tightened dump filters.

Related errors


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