Skip to content

/panel/upgrade executes upgrade scripts without authentication (missing handlePanelPageLoad) #3745

Description

@Pajt9whauht283as

Bug report (security-relevant)

/panel/upgrade executes upgrade scripts without authentication — only panel page missing handlePanelPageLoad

Affected: modules/Core/pages/panel/upgrade.php:12-17, route registered at modules/Core/module.php:111

// upgrade.php — zero authentication checks
$update_needed = DB::getInstance()->query('SELECT `value` FROM nl2_settings WHERE `name` = \'version_update\'')->first();

if (!$update_needed || ($update_needed->value !== 'true' && $update_needed->value !== 'urgent')) {
    Redirect::to(URL::build('/panel/update'));
}

Every other StaffCP page calls $user->handlePanelPageLoad(...) (e.g. update.php:22) — upgrade.php is the lone outlier, and standalone routes bypass the gated panel index entirely.

The single guard — the version_update setting — is set automatically and persistently by the hourly update check whenever any staff member views any StaffCP page (core/classes/Core/Util.php:150-157, TTL 3600s, value stored in DB until consumed).

Exploit chain (guest-level, no auth)

  1. Install runs any release older than latest upstream (extremely common).
  2. Any staff views any StaffCP page once → version_update = 'true' persists indefinitely.
  3. Guest sends GET /panel/upgradeUpgradeScript::get($version)->run() executes:
    • Phinx database schema migrations against code still on the old version (schema/app mismatch),
    • destructive helpers exist in the base class (deleteFiles, UpgradeScript.php:126-146),
    • cache→settings migrations rewrite live configuration,
    • sets nameless_version forward and clears the pending-update banner (setVersion(), :162-166) — silently consuming the admin's update state.

Integrity + availability impact on all outdated installs; no privileges needed beyond network access.

Suggested fix

Mirror update.php:22-25 at the top of the file:

if (!$user->handlePanelPageLoad('admincp.update')) {
    require_once ROOT_PATH . '/403.php';
    die();
}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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