Skip to content

Fatal error in wp-admin: Call to undefined function token_get_all() in option.lib.php (missing function_exists() guard) #219

Description

@thegushi

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

  1. Run PHP without the tokenizer extension enabled/installed.
  2. Install/activate Sucuri Scanner (or update to a version including the current option.lib.php salt/encryption logic).
  3. Load any wp-admin page.
  4. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions