phpmyfaq/phpmyfaq: User with the download attachments permission can access draft (unpublished) FAQs records
What fixes it
- 4.1.9phpmyfaq/phpmyfaq, composerGitHub
composer require "phpmyfaq/phpmyfaq:^4.1.9"
A fixed version on one release line is not the upgrade target for every line. Check your exact version and any vendor backports.
Description
Summary
The attachment download endpoint does not verify whether the attachment’s parent FAQ is published or otherwise visible to the requester. An ordinary authenticated user with the normal dlattachment ("Download attachments" ) permission can download the complete contents of an attachment belonging to a draft FAQ even though the same user receives HTTP 404 for the parent FAQ through both the page and API paths.
Details
The download is handled by the 4.1 implementation in phpmyfaq/attachment.php. Its decision checks that the attachment exists, evaluates record ACL values, and requires either dlattachment or the guest-download configuration. It does not load the parent FAQ and apply the parent’s publication-state and visibility checks.
The normal FAQ page and API do apply that visibility boundary. This creates inconsistent authorisation: the parent record is hidden while its child file remains retrievable through index.php?action=attachment&id=<ID>.
The later 4.1 commit b3654e5590066693488f71f6482dbe3d3c9a1c3c improves attachment record-ACL enforcement but does not add the missing parent-publication check. The refactored AttachmentService::canDownloadAttachment() on the tested main revision likewise lacks that check.
This appears to be a residual path related to CVE-2026-76215. That issue added parent-record checks to comments and attachment-metadata APIs, but the separate file-download path was not covered. The present path exposes complete file contents, remains present in 4.1.8, and is independently fixable.
This is distinct from CVE-2026-24420. That vulnerability allowed a user without dlattachment to bypass a defective permission check. In this reproduction, User A legitimately possesses dlattachment, while User B without that right is correctly denied. The missing authorisation decision here is whether the attachment’s parent FAQ is published and visible.
I believe this is an independently fixable residual path related to CVE-2026-76215. Please determine whether the existing CVE should be updated or whether the distinct download endpoint, full-file impact, and affected fixed versions warrant a separate CVE. I defer to the maintainer and CNA on whether this warrants a separate CVE or an update to CVE-2026-76215.
PoC
- Through the administrator interface, create:
- An active ordinary user, User A.
- An active ordinary user, User B.
- A public category.
- FAQ ID 2 with
active='no'and the default all-users/all-groups ACL rows. - Grant User A only
right_id=36dlattachment(Download attachments). Leave User B with no rights. - Create a draft FAQ (
/admin/faq/add). Through/admin/api/content/attachments/upload, upload a text file namedcanary-c.txtto FAQ 2. The reproduced body was:
PMF-PROOF-LAB-CANARY-20260907-12345678
Confirm that the response contains attachmentId: 1, the faq_faqattachment row exists, and the file exists on disk.
- Log in as User A and request the draft FAQ:
GET /index.php?action=faq&cat=1&id=2&artlang=en HTTP/1.1
Host: <TEST_HOST>
Cookie: <USER_A_SESSION>The response is HTTP 404. /api/v3.1/faq/1/2 also returns 404.
- Using the same User A session, request the child attachment:
GET /index.php?action=attachment&id=1 HTTP/1.1
Host: <TEST_HOST>
Cookie: <USER_A_SESSION>- Observe HTTP 200,
Content-Disposition: attachment; filename="canary-c.txt",Content-Length: 39, and the exact canary body. - Repeat the download and confirm the same result.
- As User B and as an anonymous visitor, request the same attachment. Both receive the application’s attachment-error page and no canary bytes, confirming that the right gate works and isolating the missing publication check.
- Publish FAQ 2. User A now receives HTTP 200 for both the FAQ and attachment.
- Return FAQ 2 to draft status without changing its ACLs. The parent returns HTTP 404 again, but the attachment remains downloadable with identical bytes.
Sanitised request/response pairs, the upgrade record, four matching download hashes, negative controls, and screenshots are available privately.
For version phpMyFAQ 4.2.0-beta (main/4.2 development revision): Repeat above steps 1-4, instead of calling the "/index.php?action=attachment&id=1" endpoint, simply call "/attachment/1".(Its corresponding download route is /attachment/X.)
Impact
An authenticated user with ordinary attachment download permission can bypass the publication boundary of a draft FAQ and obtain its complete attached files. Draft records may contain internal documentation, confidential files, or material not intended for release.
The primary reproduction requires a low privileged authenticated user with dlattachment; it does not require admin or draft-view authority. Attachment identifiers are sequential and appear in ordinary links for published attachments, making neighboring identifiers reasonably discoverable.
When guest downloads are enabled, anonymous exposure may also be possible, but that configuration-dependent variant is not required for the primary finding and is not used for the suggested severity.
Text from GitHub Advisory Database
Affected versions 1
- phpmyfaq/phpmyfaq, composer>= 4.1.7GitHub