OSV 1.4.0 · github-reviewed · 修改于 2026-05-09 04:14
发布时间
2026-05-05 04:50
GitHub 审查时间
2026-05-05 04:50
NVD 发布时间
2026-05-07 12:16
源文件
advisories/github-reviewed/2026/05/GHSA-vgrf-pr28-vf98/GHSA-vgrf-pr28-vf98.json
The deleteProcess() action accepts a POST parameter tables[] containing arbitrary table names. These are passed directly to $forge->dropTable() without validating that the tables belong to the theme being deleted.
The deleteConfirm view correctly populates tables[] from the theme's own migration files, but the server-side deleteProcess does not verify the received values against those files. An authenticated admin can craft a POST request with arbitrary table names and drop any table in the database.
This is a real bug even within the admin trust model: the action should be scoped to the theme's own tables. The permission grants delete this theme's data", not "drop any table".
modules/Theme/Controllers/Theme.php :: deleteProcess() ~line 147
public function deleteProcess(string $slug)
{
$themeName = $slug;
$activeTheme = setting('App.siteTheme');
if ($activeTheme === $themeName) {
return redirect()->route('templateSettings')...;
}
$tablesToDrop = $this->request->getPost('tables'); // ← user-supplied, unvalidated
if (!empty($tablesToDrop) && is_array($tablesToDrop)) {
$forge = \Config\Database::forge();
$db = \Config\Database::connect();
foreach ($tablesToDrop as $table) {
if ($db->tableExists($table)) {
$forge->dropTable($table, true); // ← no whitelist check
}
}
}
/backend/themes/delete-process/<any_non_active_theme_slug>tables[]=<any_table> in POST bodyci4ms_blog (confirmed in test)ci4ms_users + ci4ms_auth_identities simultaneously — disables all authentication (confirmed)Quick note on the design intent for deleteProcess — I noticed delete_confirm.php scopes the checkboxes to the theme's own migration files, and the CHANGELOG confirms the selective deletion was intentional (admins can choose which tables to keep). The server-side deleteProcess already has all the information it needs to validate the input — deleteConfirm derives the valid table set from the migration files, deleteProcess just needs to do the same before acting on the POST. Happy to clarify if useful.