Skip to content
CVE-2026-81931 ·
Medium · August 27, 2026

Unrestricted upload of file with dangerous type in Prospero Flow CRM product photo allows stored cross-site scripting

S0
Secur0 CNA
CVE-2026-81931

Description

Unrestricted Upload of File with Dangerous Type (CWE-434) leading to stored cross-site scripting (CWE-79) in ProductSaveController::save() (app/Http/Controllers/Product/ProductSaveController.php), exposed at POST /product/save, in Prospero Flow CRM before 5.16.0, which allows any authenticated user holding the create product permission —the routine Seller role, not an administrative one— to execute arbitrary JavaScript in the application origin, by uploading a file whose content starts with a valid image header and whose client-declared filename carries an .html extension, because the photo rule in ProductRequest (nullable|image|mimes:jpeg,png,jpg,gif|max:3072) classifies the file solely by its content through UploadedFile::guessExtension() and Laravel's denylist only rejects the suffixes php, php3, php4, php5, php7, php8, phtml and phar, while the controller builds the stored filename from $photoFile->getClientOriginalExtension() —the extension declared by the client, not the already validated content type— and copies it with copy() into the public web root at public_path("asset/upload/product/$product->id"), unlike ProfileSaveController::save(), which derives the extension from the content with extension() on the same kind of resource. The file is stored as <uuid>.html and nginx serves it as static content with Content-Type: text/html without requiring a session, since its configuration only routes /index.php to PHP-FPM. This results in first-party JavaScript execution in the browser of any user who opens the photo URL, including a CompanyAdmin or a SuperAdmin following a link shared in an internal email or ticket, with the first-party trust of the CRM domain.

Vulnerability type (CWE)

CWE-434: Unrestricted Upload of File with Dangerous Type

CWE-79: Improper Neutralization of Input During Web Page Generation

Affected versions

Prospero Flow CRM in all versions before 5.16.0. The vulnerable line was introduced in commit c028795f (2021-10-01), predating the project's adoption of versioning; the first formal version already containing it is 2.0.0, set in commit dd54ad70 (2023-03-03), the first to include version.php. All five published repository tags shipped vulnerable: v1.0.0 (3.9.8), v2.0.1 (4.0.0), v4.6.0 (4.6.0), v5.5.3 (5.5.3) and v5.14.0 (5.14.0). The fixed version 5.16.0 is not tagged and no published release carries the fix. Default status: unaffected.

Score (CVSS 4.0)

Medium (4.8)

CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:A/VC:N/VI:L/VA:N/SC:N/SI:L/SA:N

Solution

Upgrade to version 5.16.0 or later by deploying from the main branch: the fix has not been tagged and the latest available release, v5.14.0, does not carry it. The fix replaces getClientOriginalExtension() with extension() in the controller and introduces the ExtensionMatchesContent rule, which rejects at validation time any mismatch between the declared extension and the actual content, but it does not remove already stored files, so review public/asset/upload/product/ for files whose extension is not jpeg, jpg, png or gif and delete them.

Patch

Commit 71b20e1a

Credits

  • Adrián García López - finder
  • Darío Rivas Quero - analyst
  • Secur0 CNA - coordinator
  • Gustavo Novaro - remediation developer

Discovery source: External

Official record: CVE-2026-81931