Skip to content

Public Tracking File Leaks Password Reset Tokens to Unauthenticated Users

High
thorsten published GHSA-j5w2-cwwj-xj7x Aug 4, 2026

Package

No package listed

Affected versions

<= v4.1.6

Patched versions

4.1.7

Description

Hi Thorsten,

I'm reporting an account-takeover issue in phpMyFAQ's user tracking feature. A public tracking file records the full query string for every visited frontend page. Password reset links put the reset signature in the query string, so when any user (including admins) opens their own reset link, any unauthenticated user can read the link from /content/core/data/trackingDDMMYYYY and use it to set a password.

Overview

The installer enables main.enableUserTracking by default. When tracking is enabled, UserSession::userTracking() appends request metadata to content/core/data/trackingDDMMYYYY. The file is inside the web root and the default Apache rules only block ZIP files under content/, so unauthenticated HTTP clients can download it.

Password reset links are shaped like:

/index.php?action=resetpw&u=<user_id>&exp=<expires>&sig=<hmac>

Opening that link causes the frontend to log the raw query string. The reset token is not consumed by viewing the reset form; it remains valid until expiry or password change. An attacker who polls the public tracking file can replay the leaked u, exp, and sig against the password reset API and take over the account.

Who Can Trigger It

An unauthenticated attacker can exploit this if:

  • User tracking is enabled (main.enableUserTracking=true; installer default).
  • The attacker can get or wait for the target user to open a valid password reset link.
  • The attacker knows or can guess the target username and email to request the reset email, or otherwise the target initiates password reset themselves.

Root Cause

Admin opens reset URL with sig in query string
        |
index.php frontend request
        |
UserSession::userTracking()
        |
writes raw QUERY_STRING to content/core/data/trackingDDMMYYYY
        |
public unauthenticated GET reads tracking file
        |
POST /api/index.php/user/password/reset changes victim password

Relevant code:

  • src/phpMyFAQ/User/UserSession.php writes $request->server->get('QUERY_STRING') into content/core/data/trackingDDMMYYYY.
  • src/phpMyFAQ/Controller/Frontend/UnauthorizedUserController.php builds reset links with u, exp, and sig in the URL and accepts them in resetPassword().
  • .htaccess does not deny non-ZIP files under content/core/data/.

Test Environment

Component Version
OS Windows 11
phpMyFAQ v4.1.6
Web Server Apache 2.4 + PHP 8.3 (Docker)
Database MariaDB 11
Lab URL http://127.0.0.1:8081 (docker-compose.yml maps 8081:80)
Mail capture Mailpit — web UI http://127.0.0.1:8025, SMTP mailpit:1025 inside Compose

Steps to Reproduce

  1. Ensure that the “Enable user tracking” option is enabled.
image
  1. Our target user for this demo is as follows:
Username | kevin-admin
Password | LabPass123!
Email | kevin-admin@example.com
  1. Browse to http://127.0.0.1:8081/forgot-password and reset the target user’s password via the “Forgot password” function.
image
  1. Verify that the email receives the password reset link.
image
  1. Simulate the admin clicking on the reset link but do not proceed to submit the new password first. (The token is still unused.)
image
  1. Without authentication, browse to the following URL GET /content/core/data/tracking<DDMMYYYY> , replacing today’s date to view the logs which contains the password reset URL of the target user.
image
  1. With the pwd reset URL details above, an attacker can simply append it to “/index.php” to access the password reset page to reset the victim’s password.
http://127.0.0.1:8081/index.php?action=resetpw&u=1&exp=1785766994&sig=308f52b5546849fae74be8ab15164c8c3645b849b825e03b595f67fc7fbf2ac6

Impact

  • Unauthenticated super-admin account takeover after a viewed reset link is logged.
  • The public tracking file can also leak other sensitive URL query material because it stores raw query strings and referers.

Credits

You may contact me at kevinpook7991@gmail.com if you have any questions or require further information regarding this report. If the vulnerability is confirmed and a CVE is assigned, I would appreciate being credited as the reporter. Thank you!

Severity

High

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
Low
Privileges required
None
User interaction
Required
Scope
Unchanged
Confidentiality
High
Integrity
High
Availability
High

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H

CVE ID

No known CVE

Weaknesses

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. Learn more on MITRE.

Insertion of Sensitive Information into Log File

The product writes sensitive information to a log file. Learn more on MITRE.

Credits