Every CVE Search/ Get API key

CVE-2026-54567

Flask-Reuploaded: Extension-denylist bypass via case-folding asymmetry in name-override path (incomplete-fix variant of CVE-2026-27641)

7.5 HighFix available

Flask-Reuploaded provides file uploads for Flask. From 1.5.0 until 1.6.0, UploadSet.save(storage, name=...) in src/flask_uploads/flask_uploads.py applies lowercase_ext to the default upload path but uses the case-preserving extension helper for a caller-supplied name before extension_allowed evaluates an AllExcept denylist. An attacker who controls the name override can use a mixed-case dangerous extension to bypass a lowercase denylist and store the file in the served upload directory. Exploitation requires a denylist configuration, a user-influenced name override, and a deployment that resolves or executes extensions case-insensitively; pure allowlists remain protected and path containment is not bypassed. On an execution-capable upload directory, the stored file can execute with the web server's privileges and affect confidentiality, integrity, and availability. This issue is fixed in version 1.6.0.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
High
Privileges needed
Low
User interaction
None

What an attacker can affect

Confidentiality
High
Integrity
High
Availability
High

Exploit likelihood

0.63%Unchanged since Sep 15, 2026
90%50%10%1%

What each source reports

CVE List Score used 7.5

Flask-Reuploaded: Extension-denylist bypass via case-folding asymmetry in name-override path (incomplete-fix variant of CVE-2026-27641)

Flask-Reuploaded provides file uploads for Flask. From 1.5.0 until 1.6.0, UploadSet.save(storage, name=...) in src/flask_uploads/flask_uploads.py applies lowercase_ext to the default upload path but uses the case-preserving extension helper for a caller-supplied name before extension_allowed evaluates an AllExcept denylist. An attacker who controls the name override can use a mixed-case dangerous extension to bypass a lowercase denylist and store the file in the served upload directory. Exploitation requires a denylist configuration, a user-influenced name override, and a deployment that resolves or executes extensions case-insensitively; pure allowlists remain protected and path containment is not bypassed. On an execution-capable upload directory, the stored file can execute with the web server's privileges and affect confidentiality, integrity, and availability. This issue is fixed in version 1.6.0.

Record
CVE-2026-54567
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-178, CWE-434
Updated
2026-11-02
EUVDEUVD-2026-77683 7.5

Flask-Reuploaded provides file uploads for Flask. From 1.5.0 until 1.6.0, UploadSet.save(storage, name=...) in src/flask_uploads/flask_uploads.py applies lowercase_ext to the default upload path but uses the case-preserving extension helper for a caller-supplied name before extension_allowed evaluates an AllExcept denylist. An attacker who controls the name override can use a mixed-case dangerous extension to bypass a lowercase denylist and store the file in the served upload directory. Exploitation requires a denylist configuration, a user-influenced name override, and a deployment that resolves or executes extensions case-insensitively; pure allowlists remain protected and path containment is not bypassed. On an execution-capable upload directory, the stored file can execute with the web server's privileges and affect confidentiality, integrity, and availability. This issue is fixed in version 1.6.0.

Record
EUVD-2026-77683
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H
Updated
2026-11-02
GitHub AdvisoriesGHSA-937x-gpqr-72gg 7.5

Flask-Reuploaded: Extension-denylist bypass via case-folding asymmetry in name-override path (incomplete-fix variant of CVE-2026-27641)

1. Header

| Field | Value | |---|---| | Title | Extension-denylist bypass via case-folding asymmetry in name-override path (incomplete-fix variant of CVE-2026-27641) | | Project | Flask-Reuploaded (flask_uploads) | | Affected | <= 1.5.0 (latest release; commit ae31c3f91da40b465ca5e8f57d93f063b4553e23) | | Relationship | Incomplete-fix variant of CVE-2026-27641 (fixed in v1.5.0; this variant survives that fix) | | CWE | CWE-434 (Unrestricted Upload of File with Dangerous Type) + CWE-178 (Improper Handling of Case Sensitivity) | | CVSS v3.1 (proposed) | ~7.0–7.3 (High, conditional) — CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H. Final score deferred to maintainer. | | Verified against | pip install Flask-Reuploaded==1.5.0, Python 3.11 |


2. Decisive evidence — the asymmetry

The v1.5.0 fix for CVE-2026-27641 added an extension re-validation that runs when a caller supplies a name override to UploadSet.save(). It is routed through the case-preserving extension() helper, whereas the default upload path normalizes to lowercase via lowercase_ext() (inside get_basename()). The two paths disagree on case:

default path     : get_basename("shell.PHP")
                   = lowercase_ext(secure_filename("shell.PHP")) = "shell.php"
                   -> extension("shell.php") = "php"
                   -> extension_allowed("php")  -> DENY      (correct)

name-override    : secure_filename("shell.PHP") = "shell.PHP"   (case preserved)
                   -> basename = "shell.PHP"
                   -> ext = extension("shell.PHP") = "PHP"        (NOT lowercased)
                   -> extension_allowed("PHP")  -> ALLOW         (bypass)

On a denylist UploadSet the allow-check returns True for the mixed-case form:

# extensions.py:97
def __contains__(self, item): return item not in self.items
# "PHP" not in ('js','php','pl','py','rb','sh')  ->  True   ->  allowed

extension_allowed("PHP") passes the denylist that extension_allowed("php") is blocked by.


3. Vulnerability summary

UploadSet.save(storage, name=...) lets the caller override the stored filename. After the CVE-2026-27641 fix, name is sanitized with secure_filename() and its extension re-validated. Because the re-validation compares a case-preserving extension against a policy whose denied tokens are lowercase, an attacker controlling name stores a file with a denied extension by varying case (shell.PHP, evil.pHp). On servers that resolve/execute extensions case-insensitively (Windows/macOS filesystems; Apache AddHandler/AddType), this re-enables the dangerous-upload → code-execution outcome the parent CVE addressed. The bypassed config is the one the library's own docs recommend for blocking scripts (see §6).


4. Affected components

Permalinks pinned to commit ae31c3f91da40b465ca5e8f57d93f063b4553e23 (v1.5.0).

| Role | Location | |---|---| | Normalizing helper (default path) | src/flask_uploads/flask_uploads.py:283 — return lowercase_ext(secure_filename(filename)) | | save() entry | src/flask_uploads/flask_uploads.py:285 | | name-override sanitize | src/flask_uploads/flask_uploads.py:333 — name = secure_filename(name) | | name-override assign (case kept) | src/flask_uploads/flask_uploads.py:341 — basename = name | | Re-validation (non-normalizing) | src/flask_uploads/flask_uploads.py:344 — ext = extension(basename) | | Allow-check | src/flask_uploads/flask_uploads.py:345 | | Policy check | src/flask_uploads/flask_uploads.py:268 — extension_allowed | | Containment backstop (path only) | src/flask_uploads/flask_uploads.py:364 | | Sink | src/flask_uploads/flask_uploads.py:374 — storage.save(target) | | Case-preserving extractor | src/flask_uploads/extensions.py:101 — def extension | | Case-normalizing extractor | src/flask_uploads/extensions.py:109 — def lowercase_ext | |…

Record
GHSA-937x-gpqr-72gg
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-178, CWE-434
Updated
2026-11-02
NVD 7.5

Flask-Reuploaded provides file uploads for Flask. From 1.5.0 until 1.6.0, UploadSet.save(storage, name=...) in src/flask_uploads/flask_uploads.py applies lowercase_ext to the default upload path but uses the case-preserving extension helper for a caller-supplied name before extension_allowed evaluates an AllExcept denylist. An attacker who controls the name override can use a mixed-case dangerous extension to bypass a lowercase denylist and store the file in the served upload directory. Exploitation requires a denylist configuration, a user-influenced name override, and a deployment that resolves or executes extensions case-insensitively; pure allowlists remain protected and path containment is not bypassed. On an execution-capable upload directory, the stored file can execute with the web server's privileges and affect confidentiality, integrity, and availability. This issue is fixed in version 1.6.0.

Record
CVE-2026-54567
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-178, CWE-434
Updated
2026-11-02
OSV 7.5

Flask-Reuploaded: Extension-denylist bypass via case-folding asymmetry in name-override path (incomplete-fix variant of CVE-2026-27641)

Flask-Reuploaded provides file uploads for Flask. From 1.5.0 until 1.6.0, UploadSet.save(storage, name=...) in src/flask_uploads/flask_uploads.py applies lowercase_ext to the default upload path but uses the case-preserving extension helper for a caller-supplied name before extension_allowed evaluates an AllExcept denylist. An attacker who controls the name override can use a mixed-case dangerous extension to bypass a lowercase denylist and store the file in the served upload directory. Exploitation requires a denylist configuration, a user-influenced name override, and a deployment that resolves or executes extensions case-insensitively; pure allowlists remain protected and path containment is not bypassed. On an execution-capable upload directory, the stored file can execute with the web server's privileges and affect confidentiality, integrity, and availability. This issue is fixed in version 1.6.0.

Record
CVE-2026-54567
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-178, CWE-434
Updated
2026-11-02
OSVGHSA-937x-gpqr-72gg 7.5

Flask-Reuploaded: Extension-denylist bypass via case-folding asymmetry in name-override path (incomplete-fix variant of CVE-2026-27641)

1. Header

| Field | Value | |---|---| | Title | Extension-denylist bypass via case-folding asymmetry in name-override path (incomplete-fix variant of CVE-2026-27641) | | Project | Flask-Reuploaded (flask_uploads) | | Affected | <= 1.5.0 (latest release; commit ae31c3f91da40b465ca5e8f57d93f063b4553e23) | | Relationship | Incomplete-fix variant of CVE-2026-27641 (fixed in v1.5.0; this variant survives that fix) | | CWE | CWE-434 (Unrestricted Upload of File with Dangerous Type) + CWE-178 (Improper Handling of Case Sensitivity) | | CVSS v3.1 (proposed) | ~7.0–7.3 (High, conditional) — CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H. Final score deferred to maintainer. | | Verified against | pip install Flask-Reuploaded==1.5.0, Python 3.11 |


2. Decisive evidence — the asymmetry

The v1.5.0 fix for CVE-2026-27641 added an extension re-validation that runs when a caller supplies a name override to UploadSet.save(). It is routed through the case-preserving extension() helper, whereas the default upload path normalizes to lowercase via lowercase_ext() (inside get_basename()). The two paths disagree on case:

default path     : get_basename("shell.PHP")
                   = lowercase_ext(secure_filename("shell.PHP")) = "shell.php"
                   -> extension("shell.php") = "php"
                   -> extension_allowed("php")  -> DENY      (correct)

name-override    : secure_filename("shell.PHP") = "shell.PHP"   (case preserved)
                   -> basename = "shell.PHP"
                   -> ext = extension("shell.PHP") = "PHP"        (NOT lowercased)
                   -> extension_allowed("PHP")  -> ALLOW         (bypass)

On a denylist UploadSet the allow-check returns True for the mixed-case form:

# extensions.py:97
def __contains__(self, item): return item not in self.items
# "PHP" not in ('js','php','pl','py','rb','sh')  ->  True   ->  allowed

extension_allowed("PHP") passes the denylist that extension_allowed("php") is blocked by.


3. Vulnerability summary

UploadSet.save(storage, name=...) lets the caller override the stored filename. After the CVE-2026-27641 fix, name is sanitized with secure_filename() and its extension re-validated. Because the re-validation compares a case-preserving extension against a policy whose denied tokens are lowercase, an attacker controlling name stores a file with a denied extension by varying case (shell.PHP, evil.pHp). On servers that resolve/execute extensions case-insensitively (Windows/macOS filesystems; Apache AddHandler/AddType), this re-enables the dangerous-upload → code-execution outcome the parent CVE addressed. The bypassed config is the one the library's own docs recommend for blocking scripts (see §6).


4. Affected components

Permalinks pinned to commit ae31c3f91da40b465ca5e8f57d93f063b4553e23 (v1.5.0).

| Role | Location | |---|---| | Normalizing helper (default path) | src/flask_uploads/flask_uploads.py:283 — return lowercase_ext(secure_filename(filename)) | | save() entry | src/flask_uploads/flask_uploads.py:285 | | name-override sanitize | src/flask_uploads/flask_uploads.py:333 — name = secure_filename(name) | | name-override assign (case kept) | src/flask_uploads/flask_uploads.py:341 — basename = name | | Re-validation (non-normalizing) | src/flask_uploads/flask_uploads.py:344 — ext = extension(basename) | | Allow-check | src/flask_uploads/flask_uploads.py:345 | | Policy check | src/flask_uploads/flask_uploads.py:268 — extension_allowed | | Containment backstop (path only) | src/flask_uploads/flask_uploads.py:364 | | Sink | src/flask_uploads/flask_uploads.py:374 — storage.save(target) | | Case-preserving extractor | src/flask_uploads/extensions.py:101 — def extension | | Case-normalizing extractor | src/flask_uploads/extensions.py:109 — def lowercase_ext | |…

Record
GHSA-937x-gpqr-72gg
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-178, CWE-434
Updated
2026-11-02
OSVPYSEC-2026-3466 7.5

Flask-Reuploaded: Extension-denylist bypass via case-folding asymmetry in name-override path (incomplete-fix variant of CVE-2026-27641)

1. Header

| Field | Value | |---|---| | Title | Extension-denylist bypass via case-folding asymmetry in name-override path (incomplete-fix variant of CVE-2026-27641) | | Project | Flask-Reuploaded (flask_uploads) | | Affected | <= 1.5.0 (latest release; commit ae31c3f91da40b465ca5e8f57d93f063b4553e23) | | Relationship | Incomplete-fix variant of CVE-2026-27641 (fixed in v1.5.0; this variant survives that fix) | | CWE | CWE-434 (Unrestricted Upload of File with Dangerous Type) + CWE-178 (Improper Handling of Case Sensitivity) | | CVSS v3.1 (proposed) | ~7.0–7.3 (High, conditional) — CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H. Final score deferred to maintainer. | | Verified against | pip install Flask-Reuploaded==1.5.0, Python 3.11 |


2. Decisive evidence — the asymmetry

The v1.5.0 fix for CVE-2026-27641 added an extension re-validation that runs when a caller supplies a name override to UploadSet.save(). It is routed through the case-preserving extension() helper, whereas the default upload path normalizes to lowercase via lowercase_ext() (inside get_basename()). The two paths disagree on case:

default path     : get_basename("shell.PHP")
                   = lowercase_ext(secure_filename("shell.PHP")) = "shell.php"
                   -> extension("shell.php") = "php"
                   -> extension_allowed("php")  -> DENY      (correct)

name-override    : secure_filename("shell.PHP") = "shell.PHP"   (case preserved)
                   -> basename = "shell.PHP"
                   -> ext = extension("shell.PHP") = "PHP"        (NOT lowercased)
                   -> extension_allowed("PHP")  -> ALLOW         (bypass)

On a denylist UploadSet the allow-check returns True for the mixed-case form:

# extensions.py:97
def __contains__(self, item): return item not in self.items
# "PHP" not in ('js','php','pl','py','rb','sh')  ->  True   ->  allowed

extension_allowed("PHP") passes the denylist that extension_allowed("php") is blocked by.


3. Vulnerability summary

UploadSet.save(storage, name=...) lets the caller override the stored filename. After the CVE-2026-27641 fix, name is sanitized with secure_filename() and its extension re-validated. Because the re-validation compares a case-preserving extension against a policy whose denied tokens are lowercase, an attacker controlling name stores a file with a denied extension by varying case (shell.PHP, evil.pHp). On servers that resolve/execute extensions case-insensitively (Windows/macOS filesystems; Apache AddHandler/AddType), this re-enables the dangerous-upload → code-execution outcome the parent CVE addressed. The bypassed config is the one the library's own docs recommend for blocking scripts (see §6).


4. Affected components

Permalinks pinned to commit ae31c3f91da40b465ca5e8f57d93f063b4553e23 (v1.5.0).

| Role | Location | |---|---| | Normalizing helper (default path) | src/flask_uploads/flask_uploads.py:283 — return lowercase_ext(secure_filename(filename)) | | save() entry | src/flask_uploads/flask_uploads.py:285 | | name-override sanitize | src/flask_uploads/flask_uploads.py:333 — name = secure_filename(name) | | name-override assign (case kept) | src/flask_uploads/flask_uploads.py:341 — basename = name | | Re-validation (non-normalizing) | src/flask_uploads/flask_uploads.py:344 — ext = extension(basename) | | Allow-check | src/flask_uploads/flask_uploads.py:345 | | Policy check | src/flask_uploads/flask_uploads.py:268 — extension_allowed | | Containment backstop (path only) | src/flask_uploads/flask_uploads.py:364 | | Sink | src/flask_uploads/flask_uploads.py:374 — storage.save(target) | | Case-preserving extractor | src/flask_uploads/extensions.py:101 — def extension | | Case-normalizing extractor | src/flask_uploads/extensions.py:109 — def lowercase_ext | |…

Record
PYSEC-2026-3466
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
flask-reuploaded
PyPI
through 1.5.0
1.6.0
flask-reuploaded
PyPI
before 1.6.0, plus listed versions
0.30.3.10.3.20.4.00.5.0
Show 6 moreShow less
1.0.01.1.01.2.01.3.01.4.01.5.0
1.6.0

History

History
RecordedChangedSources
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-54567 is a high vulnerability (CVSS 7.5) in Jugmac00 Flask-reuploaded, published July 17, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.63%, the 50th percentile. Fixed in flask-reuploaded 1.6.0.

References

This page doesn't list everything

Left out here: the rest of 3 source descriptions. The JSON record has them.

MoveEnter Open