Skip to content

Unsafe Dynamic Class Instantiation in Admin Settings Allows Potential Remote Code Execution

Moderate
MrWeez published GHSA-vcg3-fjrx-rg5q May 8, 2026

Package

composer CtrlPanel-gg/panel (Composer)

Affected versions

<= 1.1.1

Patched versions

1.2.0

Description

Summary

The admin settings update endpoint accepted a fully qualified class name
directly from user-supplied request input and used it for dynamic static
method calls and object instantiation without any allowlist validation.
An authenticated admin-level user could supply an arbitrary class name
available in the Composer autoloader, potentially triggering unintended
constructor or magic method execution.

Details

In app/Http/Controllers/Admin/SettingsController.php, the update()
method read settings_class directly from the HTTP request and passed
it to new $settings_class() and $settings_class::getValidations()
without verifying that the provided value corresponds to a legitimate
settings class:

// Vulnerable code (before fix)
$settings_class = (string) request()->get('settings_class');

if (method_exists($settings_class, 'getValidations')) {
    $validations = $settings_class::getValidations();
}

$settingsClass = new $settings_class();

Because PHP resolves class names against the Composer autoloader at
runtime, any autoloadable class in the application or its dependencies
could be instantiated. Depending on the classes available in the
dependency tree, this can trigger unintended side effects through
constructors or magic methods (__construct, __toString, __wakeup),
following a PHP object injection / gadget chain pattern.

There was no allowlist, interface check, or category-to-class binding
in place prior to the fix.

PoC

  1. Log in as a user with admin settings write permission.
  2. Send the following POST request with a valid CSRF token:
POST /admin/settings HTTP/1.1
Host: <panel_url>
Cookie: <admin_session_cookie>
Content-Type: application/x-www-form-urlencoded

_token=<csrf_token>&category=general&settings_class=Some\Autoloadable\VendorClass
  1. Observe that the server accepts the request and attempts to instantiate
    the provided class rather than rejecting it as invalid.

Expected behavior: request is rejected unless settings_class matches
the server-side resolved class for the given category.

Observed behavior: the value from the request is used directly for
static calls and object instantiation.

Impact

An authenticated attacker with admin settings access can force the
application to instantiate arbitrary autoloadable classes. The practical
impact depends on the classes available in the Composer dependency tree:

  • In the worst case - if a suitable gadget chain exists among
    installed dependencies, this can lead to remote code execution,
    arbitrary file read/write, or server-side request forgery
  • In all cases - unintended constructor side effects can cause
    application instability or information disclosure

Risk is elevated in environments with broad admin delegation or where
admin credentials may be compromised.

Remediation

The fix introduces a server-side category-to-class map built by scanning
app/Settings and extension settings classes, filtered to only include
subclasses of Spatie\LaravelSettings\Settings. The settings_class
value from the request is then validated against this map before any
instantiation occurs:

$category = strtolower((string) $request->input('category'));
$settingsClassMap = $this->getSettingsCategoryClassMap();

if (!isset($settingsClassMap[$category])) {
    abort(400, 'Invalid settings category.');
}

$resolvedSettingsClass = $settingsClassMap[$category];
$requestedSettingsClass = (string) $request->input('settings_class');

if ($requestedSettingsClass !== $resolvedSettingsClass) {
    abort(400, 'Invalid settings class.');
}

This ensures that only legitimate settings classes can be instantiated,
regardless of what the request contains.

Severity

Moderate

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
High
Privileges required
High
User interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
High
Availability
High

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:H/I:H/A:H

CVE ID

CVE-2026-34216

Weaknesses

Use of Externally-Controlled Input to Select Classes or Code ('Unsafe Reflection')

The product uses external input with reflection to select which classes or code to use, but it does not sufficiently prevent the input from selecting improper classes or code. Learn more on MITRE.

Credits