Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/static-classes-none-typeerror.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Fixed a `TypeError` on PHP 8 when `Security::$static_classes` was set to a non-array value (e.g. the string `'none'`) to disable static class access; any non-array value now cleanly denies access. Use `Security::$static_classes = null` to disable access to all static classes.
8 changes: 6 additions & 2 deletions src/Security.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class Security {
/**
* This is an array of trusted static classes.
* If empty access to all static classes is allowed.
* If set to 'none' none is allowed.
* To disable access to all static classes set $static_classes = null.
*
* @var array
*/
Expand Down Expand Up @@ -206,7 +206,11 @@ public function __construct(Smarty $smarty) {
* @return boolean true if class is trusted
*/
public function isTrustedStaticClass($class_name, $compiler) {
if (isset($this->static_classes)
// Only an array enables access: an empty array allows all classes, a
// populated array is an allowlist. Any other value (null, or the
// documented "none") denies all. Using is_array() rather than isset()
// also avoids a PHP 8 TypeError from passing a non-array to in_array().
if (is_array($this->static_classes)
&& (empty($this->static_classes) || in_array($class_name, $this->static_classes))
) {
return true;
Expand Down
33 changes: 33 additions & 0 deletions tests/UnitTests/SecurityTests/SecurityTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,39 @@ public function testNotTrustedStaticClassSmartyVar()
$this->smarty->fetch('string:{$smarty.template_object::square(5)}');
}

/**
* The default (empty array) allows access to all static classes. Documents
* the backwards-compatible behaviour.
*/
public function testStaticClassAllowedByDefault()
{
$this->smarty->security_policy->static_classes = array();
$this->assertEquals('25', $this->smarty->fetch('string:{mysecuritystaticclass::square(5)}'));
}

/**
* Setting static_classes to null disables access to all static classes.
*/
public function testStaticClassDeniedWhenNull()
{
$this->expectException(\Smarty\Exception::class);
$this->expectExceptionMessage("access to static class 'mysecuritystaticclass' not allowed by security setting");
$this->smarty->security_policy->static_classes = null;
$this->smarty->fetch('string:{mysecuritystaticclass::square(5)}');
}

/**
* Regression: a non-array value such as the string 'none' must deny access
* cleanly instead of raising a PHP 8 TypeError from in_array().
*/
public function testStaticClassDeniedWhenNonArray()
{
$this->expectException(\Smarty\Exception::class);
$this->expectExceptionMessage("access to static class 'mysecuritystaticclass' not allowed by security setting");
$this->smarty->security_policy->static_classes = 'none';
$this->smarty->fetch('string:{mysecuritystaticclass::square(5)}');
}

public function testChangedTrustedDirectory()
{
$this->smarty->security_policy->secure_dir = array(
Expand Down
Loading