Summary
Upgrading to 2.7 requires a new PHP function that comes from an optional library. Breaks if you don't have tokenizer extension installed in PHP.
Sucuri Scanner throws an uncaught fatal error on every wp-admin page load when the PHP tokenizer extension is not installed/enabled. This appears to stem from the WAF API key / salt encryption changes in 2.7-2.7.2. The frontend site loads fine -- only wp-admin is affected, since the code path only runs on admin-side hooks.
Environment
- Plugin version: as of 2.7.x (encountered on a build including the isOffsetInsidePhp() salt-writing logic)
- OS: FreeBSD, PHP installed via pkg
- ext-tokenizer not installed (not a default/bundled extension on this platform)
- WordPress: wp-admin only affected; frontend unaffected
Steps to reproduce
- Run PHP without the tokenizer extension enabled/installed.
- Install/activate Sucuri Scanner (or update to a version including the current option.lib.php salt/encryption logic).
- Load any wp-admin page.
- Site returns "A critical error has occurred" -- no frontend impact.
Error / stack trace
PHP Fatal error: Uncaught Error: Call to undefined function token_get_all() in wp-content/plugins/sucuri-scanner/src/option.lib.php:768
Stack trace:
#0 option.lib.php(1019): SucuriScanOption::isOffsetInsidePhp()
#1 option.lib.php(1101): SucuriScanOption::writePluginSaltToConfig()
#2 option.lib.php(1131): SucuriScanOption::getPluginSaltRaw()
#3 option.lib.php(1183): SucuriScanOption::getSecretEncryptionKey()
#4 option.lib.php(1505): SucuriScanOption::encryptSecretValue()
#5 option.lib.php(1591): SucuriScanOption::updateSecretOption()
#6 option.lib.php(1749): SucuriScanOption::getSecretOptionValue()
#7 interface.lib.php(387): SucuriScanOption::getOption()
#8 interface.lib.php(394): SucuriScanInterface::isPremium()
#9 interface.lib.php(67): SucuriScanInterface::getPreferredTheme()
#10 class-wp-hook.php(341): SucuriScanInterface::enqueueScripts()
...
#13 wp-admin/admin-header.php(123): do_action()
#14 wp-admin/index.php(137): require_once(...)
Root cause
isOffsetInsidePhp() calls token_get_all() unconditionally. This is part of the PHP Tokenizer extension, which is not a core-always-present extension -- it's commonly excluded on minimal/ports-based PHP installs (FreeBSD ports, some hardened Linux configs, slim Docker images, etc.). When missing, PHP throws an uncaught Error rather than a catchable Exception, taking down the entire wp-admin dashboard with no graceful degradation.
Suggested fix
- Guard the call with function_exists('token_get_all') and fail soft (skip/log, don't fatal) if unavailable, since this appears to support only the salt-in-wp-config write path, not core plugin functionality.
- Alternatively/additionally, declare ext-tokenizer as a requirement in composer.json / plugin requirements so environments missing it get flagged before activation rather than fataling on the dashboard.
Impact
A security plugin should not be able to fatal a site's entire admin panel due to an unguarded call to a non-critical, non-core PHP extension. This is a particularly bad failure mode for a security-focused plugin, since it can lock admins out of their own dashboard with no clear indication of the cause outside the raw PHP error log.
Summary
Upgrading to 2.7 requires a new PHP function that comes from an optional library. Breaks if you don't have tokenizer extension installed in PHP.
Sucuri Scanner throws an uncaught fatal error on every wp-admin page load when the PHP tokenizer extension is not installed/enabled. This appears to stem from the WAF API key / salt encryption changes in 2.7-2.7.2. The frontend site loads fine -- only wp-admin is affected, since the code path only runs on admin-side hooks.
Environment
Steps to reproduce
Error / stack trace
PHP Fatal error: Uncaught Error: Call to undefined function token_get_all() in wp-content/plugins/sucuri-scanner/src/option.lib.php:768
Stack trace:
#0 option.lib.php(1019): SucuriScanOption::isOffsetInsidePhp()
#1 option.lib.php(1101): SucuriScanOption::writePluginSaltToConfig()
#2 option.lib.php(1131): SucuriScanOption::getPluginSaltRaw()
#3 option.lib.php(1183): SucuriScanOption::getSecretEncryptionKey()
#4 option.lib.php(1505): SucuriScanOption::encryptSecretValue()
#5 option.lib.php(1591): SucuriScanOption::updateSecretOption()
#6 option.lib.php(1749): SucuriScanOption::getSecretOptionValue()
#7 interface.lib.php(387): SucuriScanOption::getOption()
#8 interface.lib.php(394): SucuriScanInterface::isPremium()
#9 interface.lib.php(67): SucuriScanInterface::getPreferredTheme()
#10 class-wp-hook.php(341): SucuriScanInterface::enqueueScripts()
...
#13 wp-admin/admin-header.php(123): do_action()
#14 wp-admin/index.php(137): require_once(...)
Root cause
isOffsetInsidePhp() calls token_get_all() unconditionally. This is part of the PHP Tokenizer extension, which is not a core-always-present extension -- it's commonly excluded on minimal/ports-based PHP installs (FreeBSD ports, some hardened Linux configs, slim Docker images, etc.). When missing, PHP throws an uncaught Error rather than a catchable Exception, taking down the entire wp-admin dashboard with no graceful degradation.
Suggested fix
Impact
A security plugin should not be able to fatal a site's entire admin panel due to an unguarded call to a non-critical, non-core PHP extension. This is a particularly bad failure mode for a security-focused plugin, since it can lock admins out of their own dashboard with no clear indication of the cause outside the raw PHP error log.