Skip to main content
Vulnerability Database/CVE-2026-54567

CVE-2026-54567: Flask-Reuploaded RCE Vulnerability

CVE-2026-54567 is a remote code execution flaw in Flask-Reuploaded that allows attackers to bypass extension denylists using mixed-case filenames. This post explains its impact, affected versions, and mitigation steps.

Published:

CVE-2026-54567 Overview

Flask-Reuploaded, a file upload extension for the Flask web framework, contains an extension-denylist bypass in versions 1.5.0 through 1.5.x. The UploadSet.save(storage, name=...) function in src/flask_uploads/flask_uploads.py applies lowercase_ext to the default upload path but preserves case for caller-supplied name overrides. The extension_allowed check then evaluates an AllExcept denylist against a mixed-case extension. Attackers who control the name parameter can supply a mixed-case dangerous extension to bypass a lowercase denylist and write files to the served upload directory. The issue is fixed in version 1.6.0.

Critical Impact

On upload directories configured to execute scripts, stored files can run with the web server's privileges, compromising confidentiality, integrity, and availability.

Affected Products

  • Flask-Reuploaded 1.5.0
  • Flask-Reuploaded versions after 1.5.0 and prior to 1.6.0
  • Flask applications using AllExcept denylist configurations with user-influenced name overrides

Discovery Timeline

  • 2026-09-14 - CVE CVE-2026-54567 published to NVD
  • 2026-09-16 - Last updated in NVD database

Technical Details for CVE-2026-54567

Vulnerability Analysis

The vulnerability is a case-folding asymmetry classified under [CWE-178] (Improper Handling of Case Sensitivity). Flask-Reuploaded normalizes extensions to lowercase along the default filename code path but skips this normalization when a caller passes an explicit name override to UploadSet.save(). The extension_allowed function then compares the case-preserved extension against a denylist that assumes lowercase input. An attacker submitting shell.PHP or payload.PhTml can slip past a denylist that only blocks php or phtml. The file is then written to the served upload directory using the original casing.

Root Cause

The root cause is inconsistent application of the lowercase_ext() helper. The default write path invokes it before validation, while the name override branch uses a case-preserving extension helper. Because extension_allowed performs string comparison against a normalized denylist, any capital letter in the attacker-controlled extension defeats the check. Pure allowlists remain safe because unrecognized casings fail the inclusion test rather than passing a denylist.

Attack Vector

Exploitation requires three preconditions: a denylist (AllExcept) configuration, a user-influenced name parameter passed to UploadSet.save(), and a deployment where the web server or interpreter resolves file extensions case-insensitively. Common Apache and IIS configurations satisfy the third condition. Path containment is not bypassed, so the file lands inside the configured upload directory. If that directory is execution-capable, the uploaded script runs under the web server's user context on the next request.

text
// Security patch note from CHANGES.rst
1.6.0 (unreleased)
------------------
- **SECURITY FIX**: Ensure overridden file names are normalized via
  ``lowercase_ext()`` prior to extension validation checking and writing to
  disk.

Source: GitHub Commit 5ded760

Detection Methods for CVE-2026-54567

Indicators of Compromise

  • Files in Flask upload directories with mixed-case executable extensions such as .PHP, .PhTml, .AsPx, .JsP, or .Py
  • Web server access logs showing requests to newly created upload paths shortly after multipart form POSTs
  • Outbound network connections originating from the web server user immediately after upload activity
  • Unexpected child processes (shell, interpreter) spawned by the Flask application worker

Detection Strategies

  • Enumerate stored upload directories and flag any filename whose extension contains uppercase characters against a denylist policy
  • Instrument UploadSet.save() calls to log the resolved final filename and the source of the name argument
  • Correlate multipart upload requests with subsequent GET requests to the upload directory that trigger interpreter execution
  • Review web server module configuration for case-insensitive handler mappings that expand the exploitable surface

Monitoring Recommendations

  • Alert on process creation events where the parent is a Python or WSGI worker and the child is a shell or scripting interpreter
  • Monitor filesystem writes into static/uploads/ or equivalent served directories for extensions matching an executable denylist under any case
  • Track version metadata of flask-reuploaded across build pipelines to identify environments still running 1.5.x

How to Mitigate CVE-2026-54567

Immediate Actions Required

  • Upgrade flask-reuploaded to version 1.6.0 or later across all environments
  • Audit application code for UploadSet.save(storage, name=...) call sites where the name value derives from user input
  • Convert AllExcept denylist configurations to explicit allowlists, which remain protected even on vulnerable versions
  • Ensure upload directories are not configured as executable by the web server or interpreter

Patch Information

The fix is available in Flask-Reuploaded 1.6.0. The maintainer's commit normalizes overridden filenames through lowercase_ext() prior to extension validation and disk write. Details are documented in GitHub Security Advisory GHSA-937x-gpqr-72gg and Pull Request #186.

Workarounds

  • Replace AllExcept denylists with allowlist-based UploadSet configurations that enumerate permitted extensions
  • Strip or normalize user-supplied name arguments to lowercase before invoking UploadSet.save()
  • Configure the web server to disable script execution within upload directories using explicit handler removals
  • Serve uploaded content from a separate origin or storage bucket that cannot execute code
bash
# Pin the fixed version in requirements.txt
flask-reuploaded>=1.6.0

# Example Apache configuration to disable execution in the upload directory
# <Directory "/var/www/app/static/uploads">
#     RemoveHandler .php .phtml .phar
#     RemoveType .php .phtml .phar
#     php_flag engine off
# </Directory>

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.