twigphp/Twig · error · SecurityNotAllowedPropertyError

Calling " " property on a " " object is not allowed.

Error message

Calling "%s" property on a "%s" object is not allowed.

What it means

checkPropertyAllowed() throws SecurityNotAllowedPropertyError when sandboxed code accesses an object property that is not allowlisted for that object's class in $allowedProperties. The sandbox invokes this check before any property read on template objects.

Solutions

  1. Allow the property: $policy->setAllowedProperties([MyClass::class => ['prop', ...]]) or extend the constructor's $allowedProperties array.
  2. Catch SecurityNotAllowedPropertyError to report the class and property and update the allowlist.
  3. Pass only explicitly whitelisted view-models into sandboxed templates.
  4. Prefer allowed getter methods over raw property access if methods are already allowlisted.

Example fix

// before
 $policy = new SecurityPolicy($tags, $filters, [], [], []); // User::$name blocked
// after
 $policy->setAllowedProperties([User::class => ['name', 'email']]);
Defensive patterns

Strategy: try-catch

Validate before calling

if (!isset($allowedProperties[$obj::class]) || !in_array($prop, $allowedProperties[$obj::class], true)) {
    // access would throw; adjust policy
}

Type guard

function propertyAllowed(object $obj, string $prop, array $allowedProperties): bool {
    return in_array($prop, $allowedProperties[$obj::class] ?? [], true);
}

Try / catch

try {
    $html = $twig->render($tpl, ['user' => $userObj]);
} catch (\Twig\Sandbox\SecurityNotAllowedPropertyError $e) {
    $logger->warning('Sandbox blocked property', ['class' => $e->getClassName(), 'property' => $e->getPropertyName()]);
}

Prevention

When it happens

Trigger: A sandboxed template accesses $obj->property (directly or via {{ obj.prop }} / attribute()) where the class/property pair is missing from the policy's $allowedProperties map.

Common situations: Exposing new entities/DTOs to sandboxed templates without extending the property whitelist; refactoring classes so a formerly public property is accessed differently; strict tenant isolation policies rejecting unexpected property access.

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

Appendix: source

Thrown at src/Sandbox/SecurityPolicy.php:180

        if (!$allowed) {
            $class = $obj::class;
            throw new SecurityNotAllowedMethodError(\sprintf('Calling "%s" method on a "%s" object is not allowed.', $method, $class), $class, $method);
        }
    }

    public function checkPropertyAllowed($obj, $property): void
    {
        $allowed = false;
        foreach ($this->allowedProperties as $class => $properties) {
            if ($obj instanceof $class && \in_array($property, \is_array($properties) ? $properties : [$properties], true)) {
                $allowed = true;
                break;
            }
        }

        if (!$allowed) {
            $class = $obj::class;
            throw new SecurityNotAllowedPropertyError(\sprintf('Calling "%s" property on a "%s" object is not allowed.', $property, $class), $class, $property);
        }
    }
}

View on GitHub (pinned to a414c3a491)