Common Weakness Enumeration

CWE-436

Allowed-with-Review

Interpretation Conflict

Abstraction: Class · Status: Incomplete

Product A handles inputs or steps differently than Product B, which causes A to perform incorrect actions based on its perception of B's state.

263 vulnerabilities reference this CWE, most recent first.

GHSA-V293-3P6G-J7W7

Vulnerability from github – Published: 2024-04-10 18:30 – Updated: 2024-04-10 18:30
VLAI
Details

An incorrect string comparison vulnerability in Palo Alto Networks PAN-OS software prevents Predefined Decryption Exclusions from functioning as intended. This can cause traffic destined for domains that are not specified in Predefined Decryption Exclusions to be unintentionally excluded from decryption.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2024-3386"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-436"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2024-04-10T17:15:57Z",
    "severity": "MODERATE"
  },
  "details": "An incorrect string comparison vulnerability in Palo Alto Networks PAN-OS software prevents Predefined Decryption Exclusions from functioning as intended. This can cause traffic destined for domains that are not specified in Predefined Decryption Exclusions to be unintentionally excluded from decryption.",
  "id": "GHSA-v293-3p6g-j7w7",
  "modified": "2024-04-10T18:30:48Z",
  "published": "2024-04-10T18:30:48Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-3386"
    },
    {
      "type": "WEB",
      "url": "https://security.paloaltonetworks.com/CVE-2024-3386"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-V2HH-GCRM-F6HX

Vulnerability from github – Published: 2026-07-21 22:08 – Updated: 2026-07-21 22:08
VLAI
Summary
fast-uri vulnerable to host confusion via literal backslash authority delimiter
Details

Impact

fast-uri v4.1.0 and earlier do not treat a literal backslash (U+005C) as an authority delimiter. Node's native WHATWG URL (used by fetch(), undici, and Node's http/https clients) normalizes \ to / for special schemes (http, https, ws, wss, ftp, file), so the two parsers extract different hosts from the same input string.

For example, http://evil.com\@allowed.com is treated by fast-uri as host allowed.com with userinfo evil.com\, while Node's WHATWG URL parser and fetch() see host evil.com with path /@allowed.com.

Applications that use fast-uri to enforce host-based policy (allowlists, denylists, loopback/SSRF filtering, redirect validation, outbound proxy routing) before passing the same URL into Node's URL or fetch() consumers see a policy/use desync and can be steered to an unintended destination, including cloud metadata endpoints, loopback, or internal hosts.

Patches

Upgrade to fast-uri v4.1.1, v3.1.4, or v2.4.3.

Workarounds

None. Upgrade to the patched version.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 2.4.2"
      },
      "package": {
        "ecosystem": "npm",
        "name": "fast-uri"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "2.3.1"
            },
            {
              "fixed": "2.4.3"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 3.1.3"
      },
      "package": {
        "ecosystem": "npm",
        "name": "fast-uri"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "3.0.0"
            },
            {
              "fixed": "3.1.4"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 4.1.0"
      },
      "package": {
        "ecosystem": "npm",
        "name": "fast-uri"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "4.0.0"
            },
            {
              "fixed": "4.1.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-16221"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-436"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-07-21T22:08:28Z",
    "nvd_published_at": "2026-07-19T15:16:49Z",
    "severity": "HIGH"
  },
  "details": "### Impact\n\n`fast-uri` v4.1.0 and earlier do not treat a literal backslash (U+005C) as an authority delimiter. Node\u0027s native WHATWG `URL` (used by `fetch()`, `undici`, and Node\u0027s `http`/`https` clients) normalizes `\\` to `/` for special schemes (`http`, `https`, `ws`, `wss`, `ftp`, `file`), so the two parsers extract different hosts from the same input string.\n\nFor example, `http://evil.com\\@allowed.com` is treated by `fast-uri` as host `allowed.com` with userinfo `evil.com\\`, while Node\u0027s WHATWG URL parser and `fetch()` see host `evil.com` with path `/@allowed.com`.\n\nApplications that use `fast-uri` to enforce host-based policy (allowlists, denylists, loopback/SSRF filtering, redirect validation, outbound proxy routing) before passing the same URL into Node\u0027s URL or `fetch()` consumers see a policy/use desync and can be steered to an unintended destination, including cloud metadata endpoints, loopback, or internal hosts.\n\n### Patches\n\nUpgrade to `fast-uri` v4.1.1, v3.1.4, or v2.4.3.\n\n### Workarounds\n\nNone. Upgrade to the patched version.",
  "id": "GHSA-v2hh-gcrm-f6hx",
  "modified": "2026-07-21T22:08:29Z",
  "published": "2026-07-21T22:08:28Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/fastify/fast-uri/security/advisories/GHSA-v2hh-gcrm-f6hx"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-16221"
    },
    {
      "type": "WEB",
      "url": "https://github.com/fastify/fast-uri/commit/0542a216860fd70c062a4730e620576f62ded057"
    },
    {
      "type": "WEB",
      "url": "https://github.com/fastify/fast-uri/commit/2d50fbabc80e4d0884fe0f6a98fe118ce6faa353"
    },
    {
      "type": "WEB",
      "url": "https://github.com/fastify/fast-uri/commit/9438266d6a7ded688c8bc7c4ba506da17f44a17b"
    },
    {
      "type": "WEB",
      "url": "https://cna.openjsf.org/security-advisories.html"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/fastify/fast-uri"
    },
    {
      "type": "WEB",
      "url": "https://github.com/fastify/fast-uri/releases/tag/v2.4.3"
    },
    {
      "type": "WEB",
      "url": "https://github.com/fastify/fast-uri/releases/tag/v3.1.4"
    },
    {
      "type": "WEB",
      "url": "https://github.com/fastify/fast-uri/releases/tag/v4.1.1"
    }
  ],
  "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": "fast-uri vulnerable to host confusion via literal backslash authority delimiter"
}

GHSA-V39H-62P7-JPJC

Vulnerability from github – Published: 2026-05-08 19:13 – Updated: 2026-09-01 15:30
VLAI
Summary
fast-uri vulnerable to host confusion via percent-encoded authority delimiters
Details

Impact

fast-uri v3.1.1 and earlier decodes percent-encoded authority delimiters (%40 as @, %3A as :) inside the host component and serializes them back as raw characters. This changes the URI structure, turning a hostname into userinfo plus a different host.

For example, http://trusted.com%40evil.com/ normalizes to http://trusted.com@evil.com/, which reparses as host evil.com with userinfo trusted.com.

Applications that normalize untrusted URLs before host allowlist checks, redirect validation, or outbound request routing can be steered to a different authority than the original URL appeared to contain.

Patches

Upgrade to fast-uri >= 3.1.2, or if you are in the v2.x release line, v2.4.1

Workarounds

None. Upgrade to the patched version.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 3.1.1"
      },
      "package": {
        "ecosystem": "npm",
        "name": "fast-uri"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "3.0.0"
            },
            {
              "fixed": "3.1.2"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 2.4.0"
      },
      "package": {
        "ecosystem": "npm",
        "name": "fast-uri"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "2.4.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-6322"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-140",
      "CWE-436"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-05-08T19:13:01Z",
    "nvd_published_at": "2026-05-05T11:16:33Z",
    "severity": "HIGH"
  },
  "details": "### Impact\n\n`fast-uri` v3.1.1 and earlier decodes percent-encoded authority delimiters (`%40` as `@`, `%3A` as `:`) inside the host component and serializes them back as raw characters. This changes the URI structure, turning a hostname into userinfo plus a different host.\n\nFor example, `http://trusted.com%40evil.com/` normalizes to `http://trusted.com@evil.com/`, which reparses as host `evil.com` with userinfo `trusted.com`.\n\nApplications that normalize untrusted URLs before host allowlist checks, redirect validation, or outbound request routing can be steered to a different authority than the original URL appeared to contain.\n\n### Patches\n\nUpgrade to `fast-uri` \u003e= 3.1.2, or if you are in the v2.x release line, v2.4.1\n\n### Workarounds\n\nNone. Upgrade to the patched version.",
  "id": "GHSA-v39h-62p7-jpjc",
  "modified": "2026-09-01T15:30:39Z",
  "published": "2026-05-08T19:13:01Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/fastify/fast-uri/security/advisories/GHSA-v39h-62p7-jpjc"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-6322"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:41928"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:41951"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:42078"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:42142"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:43038"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:54395"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:54555"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:56366"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:56431"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:56928"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:56968"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:57013"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:57487"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:60520"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:60855"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:61783"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/security/cve/CVE-2026-6322"
    },
    {
      "type": "WEB",
      "url": "https://bugzilla.redhat.com/show_bug.cgi?id=2466684"
    },
    {
      "type": "WEB",
      "url": "https://cna.openjsf.org/security-advisories.html"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/fastify/fast-uri"
    },
    {
      "type": "WEB",
      "url": "https://github.com/fastify/fast-uri/releases/tag/v2.4.1"
    },
    {
      "type": "WEB",
      "url": "https://github.com/fastify/fast-uri/releases/tag/v3.1.2"
    },
    {
      "type": "WEB",
      "url": "https://security.access.redhat.com/data/csaf/v2/vex/2026/cve-2026-6322.json"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:25271"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:25273"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:26225"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:26234"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:28571"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:29197"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:29795"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:29796"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:29800"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:29834"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:30076"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:33683"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:34160"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:34342"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:34374"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:34766"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:34770"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:36651"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:36754"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:37186"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:37385"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:37628"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:40118"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:40945"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2026:41066"
    }
  ],
  "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": "fast-uri vulnerable to host confusion via percent-encoded authority delimiters"
}

GHSA-V5MV-P594-2X33

Vulnerability from github – Published: 2026-08-03 21:07 – Updated: 2026-08-03 21:07
VLAI
Summary
Guzzle: Noncanonical host can bypass host-based checks
Details

Impact

In affected versions, Guzzle gives a transport the request URI as text and supplies the Host header separately. The cURL handlers set CURLOPT_URL to the URI exactly as written and push that Host into CURLOPT_HTTPHEADER; StreamHandler does the same through fopen(). libcurl then parses the authority itself, percent-decoding it and, on an IDN-capable build, applying IDNA mapping, and uses the result to resolve, connect, name the TLS peer and address a proxy CONNECT, while the supplied Host suppresses the aligned one it would have generated. In http://127.0.0.%31/ the URI host is one filter_var() rejects as an IP literal, yet libcurl decodes it to 127.0.0.1 and reaches loopback with no DNS lookup while the server receives Host: 127.0.0.%31.

An attacker who influences a fetched URI can therefore reach a host the application's checks excluded and read whatever it exposes of the response. The same divergence moves Guzzle's own decisions onto a spelling the transport does not use: no_proxy selects proxy routing from the literal host, and RedirectMiddleware decides from it whether to strip Authorization and Cookie. The cookie middleware extracts Set-Cookie against the URI Guzzle produced, not the authority contacted, so for a raw divergent URI the cookie is stored under the URI host as written. Where Guzzle rewrote that URI but left a divergent Host, or where the caller supplied one, the cookie is stored under the canonical name and replayed by ordinary later requests to it. With a third-party UriInterface, a host of blocked.example.com@127.0.0.1 reaches 127.0.0.1 through all three handlers and generates Authorization: Basic from userinfo the application never wrote.

Exploitation requires the application to build a request URI from untrusted input and to make a host decision before handing it to Guzzle. Applications that only fetch URIs they construct themselves are not affected, and an exact allowlist of canonical names ordinarily fails closed; the exposure is to denylists, private-range and IP-literal checks, and any check that treats an unresolvable name as safe. The raw Unicode class needs an IDNA transformation somewhere: either a libcurl built with IDN support or Guzzle's own idn_conversion, off by default on both branches, which rewrites the URI in Client::buildUri() before a handler sees it and leaves a prebuilt request's explicit Host as written, while a request the client builds derives that header from the rewritten URI and produces no divergence. Noncanonical numeric spellings such as 127.1, 2130706433, 0x7f000001 and 0177.0.0.1 remain accepted after the patch and reach whatever the transport reads them as, loopback or a routable public host, and the cURL and stream handlers can differ, so a check comparing a host against an address as text stays bypassable. Guzzle does not offer SSRF protection, and neither cache poisoning nor cross-tenant compromise was established.

Patches

This is a summary; the patches are the authority. The issue is fixed in 7.15.2 and 8.0.1, which validate the request host in all three built-in handlers before any network I/O. A URI host is rejected for a byte outside 0x21 to 0x7E, a percent escape, a URI authority delimiter, unbalanced brackets, or numeric-looking parts followed by a trailing dot. That last rule is deliberately conservative and also refuses out-of-range forms libcurl keeps as names, such as 256.0.0.1.. An explicit Host header must be printable ASCII, and on 7.15.2 free of percent escapes. The client also regenerates a derived Host when it rewrites the request URI. Versions before 7.15.2 and version 8.0.0 are affected.

Workarounds

If you cannot upgrade, constrain the host yourself before handing a URI to Guzzle, and constrain any explicit Host header separately, on every redirect hop. The URI rule assumes $uri is a validated GuzzleHttp\Psr7\Uri, so re-parse a third-party UriInterface with new Uri((string) $uri) first.

$host = $uri->getHost();

if (
    preg_match('/\A[\x21-\x7E]*\z/D', $host) !== 1
    || strpbrk($host, '%@/?#\\') !== false
    || substr($host, -1) === '.'
) {
    throw new RuntimeException('Refusing to fetch this URI host.');
}

if (
    preg_match('/\A[\x21-\x7E]*\z/D', $hostHeader) !== 1
    || strpos($hostHeader, '%') !== false
) {
    throw new RuntimeException('Refusing to send this Host header.');
}

It differs from the patch in both directions: it refuses example.com., which the patch accepts, and it does not canonicalize 127.1 or 0x7f000001. Reparsing the URI separates a valid port from the host and rejects malformed bracket forms, so the snippet checks the host component alone. idn_conversion => true is not an access control, since IDNA maps 127。0。0。1 onto 127.0.0.1 and direct handler use bypasses it, and Uri::getHost() is not an SSRF boundary: it is the host as written, not the host a transport connects to. Where the destination matters, resolve the host and check the addresses, and use a separate cookie jar for untrusted origins.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "guzzlehttp/guzzle"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "7.15.2"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "guzzlehttp/guzzle"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "8.0.0"
            },
            {
              "fixed": "8.0.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-69246"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-180",
      "CWE-436",
      "CWE-918",
      "CWE-941"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-08-03T21:07:26Z",
    "nvd_published_at": null,
    "severity": "HIGH"
  },
  "details": "### Impact\n\nIn affected versions, Guzzle gives a transport the request URI as text and supplies the `Host` header separately. The cURL handlers set `CURLOPT_URL` to the URI exactly as written and push that `Host` into `CURLOPT_HTTPHEADER`; `StreamHandler` does the same through `fopen()`. libcurl then parses the authority itself, percent-decoding it and, on an IDN-capable build, applying IDNA mapping, and uses the result to resolve, connect, name the TLS peer and address a proxy `CONNECT`, while the supplied `Host` suppresses the aligned one it would have generated. In `http://127.0.0.%31/` the URI host is one `filter_var()` rejects as an IP literal, yet libcurl decodes it to `127.0.0.1` and reaches loopback with no DNS lookup while the server receives `Host: 127.0.0.%31`.\n\nAn attacker who influences a fetched URI can therefore reach a host the application\u0027s checks excluded and read whatever it exposes of the response. The same divergence moves Guzzle\u0027s own decisions onto a spelling the transport does not use: `no_proxy` selects proxy routing from the literal host, and `RedirectMiddleware` decides from it whether to strip `Authorization` and `Cookie`. The cookie middleware extracts `Set-Cookie` against the URI Guzzle produced, not the authority contacted, so for a raw divergent URI the cookie is stored under the URI host as written. Where Guzzle rewrote that URI but left a divergent `Host`, or where the caller supplied one, the cookie is stored under the canonical name and replayed by ordinary later requests to it. With a third-party `UriInterface`, a host of `blocked.example.com@127.0.0.1` reaches `127.0.0.1` through all three handlers and generates `Authorization: Basic` from userinfo the application never wrote.\n\nExploitation requires the application to build a request URI from untrusted input and to make a host decision before handing it to Guzzle. Applications that only fetch URIs they construct themselves are not affected, and an exact allowlist of canonical names ordinarily fails closed; the exposure is to denylists, private-range and IP-literal checks, and any check that treats an unresolvable name as safe. The raw Unicode class needs an IDNA transformation somewhere: either a libcurl built with IDN support or Guzzle\u0027s own `idn_conversion`, off by default on both branches, which rewrites the URI in `Client::buildUri()` before a handler sees it and leaves a prebuilt request\u0027s explicit `Host` as written, while a request the client builds derives that header from the rewritten URI and produces no divergence. Noncanonical numeric spellings such as `127.1`, `2130706433`, `0x7f000001` and `0177.0.0.1` remain accepted after the patch and reach whatever the transport reads them as, loopback or a routable public host, and the cURL and stream handlers can differ, so a check comparing a host against an address as text stays bypassable. Guzzle does not offer SSRF protection, and neither cache poisoning nor cross-tenant compromise was established.\n\n### Patches\n\nThis is a summary; the patches are the authority. The issue is fixed in `7.15.2` and `8.0.1`, which validate the request host in all three built-in handlers before any network I/O. A URI host is rejected for a byte outside `0x21` to `0x7E`, a percent escape, a URI authority delimiter, unbalanced brackets, or numeric-looking parts followed by a trailing dot. That last rule is deliberately conservative and also refuses out-of-range forms libcurl keeps as names, such as `256.0.0.1.`. An explicit `Host` header must be printable ASCII, and on `7.15.2` free of percent escapes. The client also regenerates a derived `Host` when it rewrites the request URI. Versions before `7.15.2` and version `8.0.0` are affected.\n\n### Workarounds\n\nIf you cannot upgrade, constrain the host yourself before handing a URI to Guzzle, and constrain any explicit `Host` header separately, on every redirect hop. The URI rule assumes `$uri` is a validated `GuzzleHttp\\Psr7\\Uri`, so re-parse a third-party `UriInterface` with `new Uri((string) $uri)` first.\n\n```php\n$host = $uri-\u003egetHost();\n\nif (\n    preg_match(\u0027/\\A[\\x21-\\x7E]*\\z/D\u0027, $host) !== 1\n    || strpbrk($host, \u0027%@/?#\\\\\u0027) !== false\n    || substr($host, -1) === \u0027.\u0027\n) {\n    throw new RuntimeException(\u0027Refusing to fetch this URI host.\u0027);\n}\n\nif (\n    preg_match(\u0027/\\A[\\x21-\\x7E]*\\z/D\u0027, $hostHeader) !== 1\n    || strpos($hostHeader, \u0027%\u0027) !== false\n) {\n    throw new RuntimeException(\u0027Refusing to send this Host header.\u0027);\n}\n```\n\nIt differs from the patch in both directions: it refuses `example.com.`, which the patch accepts, and it does not canonicalize `127.1` or `0x7f000001`. Reparsing the URI separates a valid port from the host and rejects malformed bracket forms, so the snippet checks the host component alone. `idn_conversion =\u003e true` is not an access control, since IDNA maps `\uff11\uff12\uff17\u3002\uff10\u3002\uff10\u3002\uff11` onto `127.0.0.1` and direct handler use bypasses it, and `Uri::getHost()` is not an SSRF boundary: it is the host as written, not the host a transport connects to. Where the destination matters, resolve the host and check the addresses, and use a separate cookie jar for untrusted origins.",
  "id": "GHSA-v5mv-p594-2x33",
  "modified": "2026-08-03T21:07:26Z",
  "published": "2026-08-03T21:07:26Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/guzzle/guzzle/security/advisories/GHSA-v5mv-p594-2x33"
    },
    {
      "type": "WEB",
      "url": "https://github.com/guzzle/guzzle/pull/3907"
    },
    {
      "type": "WEB",
      "url": "https://github.com/guzzle/guzzle/pull/3908"
    },
    {
      "type": "WEB",
      "url": "https://github.com/guzzle/guzzle/commit/3aeea0406aab88cbbd86531313d7cebf8ae149a4"
    },
    {
      "type": "WEB",
      "url": "https://github.com/guzzle/guzzle/commit/744101956d78b7c1384d0cbf379db13e859167bf"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/guzzle/guzzle"
    },
    {
      "type": "WEB",
      "url": "https://github.com/guzzle/guzzle/releases/tag/7.15.2"
    },
    {
      "type": "WEB",
      "url": "https://github.com/guzzle/guzzle/releases/tag/8.0.1"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Guzzle: Noncanonical host can bypass host-based checks"
}

GHSA-V67P-PHPQ-FC8X

Vulnerability from github – Published: 2026-09-10 23:04 – Updated: 2026-09-10 23:04
VLAI
Summary
Traefik entrypoint header-name sanitization bypassed via request trailers
Details

Summary

Traefik's entrypoint defenses against spoofed trusted header names — aliasHeadersStrategy / underscoreHeadersStrategy in delete or reject mode, and the default forwardedHeaders stripping of client-supplied X-Forwarded-* — scan req.Header only and never req.Trailer. An unauthenticated client can therefore smuggle a sanitized name (an aliasing spelling such as X_Auth_User, or a trusted name such as X-Forwarded-Prefix) as an HTTP/1.1 chunked trailer or an HTTP/2 trailer: reject does not return its documented 400, delete does not remove the name, and Traefik's reverse proxy forwarded the trailer to the backend — with an attacker-chosen value whenever a body-buffering middleware (the retry middleware with status codes, or the buffering middleware) reads the body before the proxy clone. Backends that merge trailers into their header namespace then act on the smuggled name. The fix stops forwarding request trailer values to the backend; the declared trailer names are still forwarded as permitted by RFC 9110 section 6.6.2.

Traefik v2 is not affected: the defect is in the custom reverse proxy introduced in v3 (pkg/proxy/httputil), and v2 uses the Go standard library's httputil.ReverseProxy, which does not forward request trailer values to the backend. Affected v3 lines from v3.2.0 through v3.7.12 include the end-of-life v3.2 through v3.6 lines, which will not receive a fix on their own line; the remedy for those users is to upgrade to v3.7.13.

Patches

  • https://github.com/traefik/traefik/releases/tag/v3.7.13

For more information

If you have any questions or comments about this advisory, please open an issue.

Original Description ### Summary Traefik's entrypoint defenses against spoofed header names — `aliasHeadersStrategy` / `underscoreHeadersStrategy` in `delete` or `reject` mode, and the `forwardedHeaders` handling that strips client-supplied `X-Forwarded-*` — scan `req.Header` only and never `req.Trailer`, although the handlers' own comments promise to cover "header **and trailer**". An unauthenticated client can therefore deliver the aliasing name (`X_Auth_User`, `X.Auth.User`) or the trusted name itself (`X-Forwarded-Prefix`, …) as an HTTP/1.1 chunked trailer or an HTTP/2 trailer: `reject` does not return its documented `400`, `delete` does not remove the name, and the trailer form of an `X-Forwarded-*` name passes exactly where the header form is stripped. When a body-buffering middleware is in the chain (retry with `status` codes, or the `buffering` middleware — both measured), the trailer travels **with an attacker-chosen value**; measured end-to-end against the trailer-merging component Ubuntu 24.04 ships (pre-fix libevent, CVE-2026-63379), the header `X-Forwarded-Prefix: admin` is stripped and denied while the identical name as a trailer is acted upon as admin (`403 → 200`). On bare proxy paths only the trailer name travels (no value), bounding those deployments to name-level effects. ### Details **Root cause.** All four entrypoint handlers iterate `req.Header` only — the doc comments promise more than the code does (`pkg/server/server_entrypoint_tcp.go`):
// removeAliasingHeaders removes any request header and trailer whose name contains a character
// which is neither a letter, a digit, nor a dash, as such a name aliases another header name.
func removeAliasingHeaders(h http.Handler) http.Handler {
    return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
        for key := range req.Header {          // ← req.Trailer is never scanned
            if isAliasingHeaderName(key) {
                delete(req.Header, key)
            }
        }
        h.ServeHTTP(rw, req)
    })
}
`rejectAliasingHeaders`, `removeHeadersWithUnderscores` and `rejectHeadersWithUnderscores` share the identical structure (the `reject` variants return `400` from the same loop). The sibling sanitization `forwardedheaders.DeleteXForwardedHeaders` (`pkg/middlewares/forwardedheaders/forwarded_header.go`) also scans `req.Header` only, so the trusted `X-Forwarded-*` names whose header form Traefik strips for untrusted clients — the managed `XHeadersSet`, which includes `X-Forwarded-Prefix` and `X-Forwarded-For` — survive in trailer form. Go's HTTP server populates `req.Trailer` from chunked/HTTP/2 trailers, and Traefik's proxy layer forwards those entries, bypassing the sanitization above. **Contract provenance.** The "header and trailer" wording is in the original introducing diffs — `108a52644` (underscoreHeadersStrategy) and `0331801c` (aliasHeadersStrategy) — and is unchanged in `master` (full diff excerpts available on request). The option began as `allowHeadersWithUnderscores: false` (per the CVE-2026-54763 record) before becoming `underscoreHeadersStrategy` and then `aliasHeadersStrategy`. The user-facing documentation describes only "request headers". **Mechanism (why names survive, and when values do too).** 1. *Name pre-fill at parse time.* The client's `Trailer: X_Auth_User` declaration makes Go's server move the declared keys into `req.Trailer` with nil values before the handler runs (`net/http/transfer.go`, `fixTrailer`); HTTP/2 does the same from the `trailer:` field in the initial HEADERS ("Setup Trailers", `net/http/internal/httpcommon/httpcommon.go`). The entrypoint handlers therefore cannot see the trailer name, but the proxy forwards it. Trailer keys are canonicalized with `textproto.CanonicalMIMEHeaderKey`, which treats dashes — not underscores — as case separators: the aliasing spelling survives canonicalization as e.g. `X_auth_user` (visible in the backend dumps in PoC §1) and remains detectable by `isAliasingHeaderName`, so the fix does not depend on the client's original spelling. 2. *Value survival depends on who reads the body first.* Trailer values are appended to `req.Trailer` only while the body is consumed (`readTrailer` / `copyTrailersToHandlerRequest`). On the bare path the reverse proxy calls `Request.Clone` at handler start, before any body read, so the clone captures nil values — on HTTP/1.1 the trailer field line is then omitted entirely (`net/http/header.go`, `Header.writeSubset` writes one line per value), and h2c delivers only the empty key. When a body-buffering middleware runs first, the order reverses: the retry middleware with `status` codes buffers the body via `mirror.NewReusableRequest` → `io.ReadAll(req.Body)` (`pkg/middlewares/retry/retry.go`, `pkg/server/service/loadbalancer/mirror/mirror.go`), the values are populated before `http.Request.Clone`, and they travel to the backend. Buffering triggers for idempotent methods with `status` alone; POST additionally requires `retryNonIdempotentMethod` (both measured). Retry and buffering are the two measured paths; the mirroring and failover services use the same `mirror.NewReusableRequest` helper (`pkg/server/service/loadbalancer/mirror/mirror.go`, `failover/failover.go` when `errors.status` is configured) and share its behavior (not measured). The `buffering` middleware drains the body eagerly before the proxy too: `pkg/middlewares/buffering/buffering.go` → oxy's `multibuf.New` → `ioutil.ReadAll` (github.com/mailgun/multibuf `buffer.go`; unset limits fall back to 1 MB `DefaultMemBytes`) — measured value-preserving with default limits. 3. *Undeclared trailers: transit depends on whether anything else was declared (measured).* On HTTP/2 the standard library server copies only pre-declared trailers ("Only copy it over it was pre-declared", `net/http/internal/http2/server.go`) — undeclared fields never appear. On HTTP/1.1 `readTrailer` parses the entire trailer section with no declaration filter, and `mergeSetHeader` either **rebinds** the map when nil (`*dst = src`) or blindly merges when non-nil (point 4). The rebind is why zero-declaration requests lose undeclared fields at Traefik's observability `req.WithContext` shallow copy (`pkg/middlewares/observability/observability.go`, `entrypoint.go`) — measured: they never leave the entrypoint even on buffered chains. But a **bait declaration** (any clean name, e.g. `X-Dummy`) keeps the map non-nil, and the blind merge then writes the undeclared field into the shared map at body EOF — measured on the retry-buffered chain: the backend receives `map[X-Dummy:[1] X_auth_user:[attacker-value]]` and presence-based policies flip; the bare path is unaffected and delivers only `map[X-Dummy:[]]`. 4. *Delete-mode stickiness depends on the merge semantics (measured).* `readTrailer` merges parsed trailer fields via `mergeSetHeader`, whose non-nil branch is a blind `maps.Copy` (`net/http/transfer.go`) — a key deleted by a handler is re-added **with its value** at body EOF. Measured on a bare Go server (`delete(r.Trailer, "X_auth_user")` before draining the body): HTTP/1.1 — `map[X_auth_user:[]]` → `map[X_auth_user:[attacker-value]]` (re-added); HTTP/2 — `map[X_auth_user:[]]` → `map[]` (stays deleted: `copyTrailersToHandlerRequest` checks the live map). **Deliberate trailer-forwarding behavior (regression tests).** Traefik deliberately does not forward request trailers on the bare proxy chain, locked by the regression tests `pkg/proxy/httputil/trailer_test.go` and `pkg/proxy/fast/trailer_test.go` (added `86b5642f`, 2026-06-25; extended `d427dccf`, 2026-06-29): "trailers arrive after the body, once routing and security decisions have already been made, so forwarding them could raise security concerns in Traefik." The measured buffered-chain value survival (mechanism point 2) defeats exactly that locked invariant — the tests exercise only the bare chain — and the name-level h2c forwarding (empty keys) passes the tests' assertion (`Header.Get` is empty whether the key is absent or empty-valued): neither regression test catches this finding. The value-level path thus bypasses a deliberate, test-locked security invariant. **Preconditions.** 1. An entrypoint whose sanitization is relied upon: `aliasHeadersStrategy` / `underscoreHeadersStrategy` set to `delete` or `reject`, or the default `forwardedHeaders` stripping of `X-Forwarded-*` for untrusted clients. 2. A request carrying the name as a declared trailer (HTTP/1.1 chunked, or HTTP/2), or — on HTTP/1.1 buffered chains only — as an undeclared trailer field riding a bait declaration (mechanism point 3). 3. For downstream impact: a backend that merges trailers into its header namespace (pre-fix libevent CVE-2026-63379 — still what Ubuntu 24.04 ships —, pre-fix blaze CVE-2026-73495, or custom code) or consumes trailer fields in a trust decision. 4. For the value-level path: the retry middleware with `status` codes, the `buffering` middleware, or another body-buffering middleware, in the chain. **Precedent and scope.** This is the next variant of Traefik's own aliasing family — CVE-2026-33433 (GHSA-qr99-7898-vr7c), CVE-2026-39858 (GHSA-5m6w-wvh7-57vm), CVE-2026-54763 (GHSA-x677-9fxg-v5c5) — and Traefik's Security Decisions state the in-scope line: "a spelling that survives the entrypoint sanitisation and still reaches the backend as the trusted name". The trailer spelling is precisely that. The downstream merge class is cross-ecosystem: libevent CVE-2026-63379 (run live in PoC §3) and blaze/http4s CVE-2026-73495 (GHSA-46q4-43ph-c6fr, fixed `ef3e666`). **Boundaries (measured).** Declaring `Content-Length`, `Transfer-Encoding` or `Trailer` as trailer fields is rejected with `400` by Go's server; `Host` and `Connection` pass through name-level. The FastProxy forwarding mode (opt-in `[experimental] fastProxy`) does not forward trailers; the default reverse-proxy path for `http://` backends does (PoC §3). HTTP/3 (quic-go) trailer semantics are untested. Undeclared trailers: HTTP/2 drops them entirely; on HTTP/1.1 they transit only via a bait declaration on buffered chains (mechanism point 3). ### PoC Verified against a source-built Traefik (`master` @ `237f13c6`, built with **Go 1.27.0**; all harness backends built with Go 1.27.0 — the trailer behaviors cited in Details are version-sensitive `net/http` internals). Complete harness (clients, backends, configs, logs) available on request; the raw chunked requests below are HTTP/1.1 and reproducible with `nc`/`python`. **1. Core bypass (`aliasHeadersStrategy = reject`).** Static config:
[entryPoints.web]
  address = ":8090"
  [entryPoints.web.http]
    aliasHeadersStrategy = "reject"

[providers.file]
  filename = "dynamic.toml"
  watch = true
`dynamic.toml`: router `PathPrefix(`/`)` → service → `h2c://127.0.0.1:8081` (a Go echo backend that drains the body and prints `r.Trailer`). Requests (CRLF line endings; `5`/`0` are chunk sizes):
POST / HTTP/1.1
Host: 127.0.0.1:8090
Connection: close
Transfer-Encoding: chunked
Trailer: X_Auth_User

5
hello
0
X_Auth_User: attacker-value

Results:
header  X_Auth_User   (curl -H "X_Auth_User: x")  → HTTP 400  (rejected, as designed)
trailer X_Auth_User   (request above)             → HTTP 200  (bypass: not rejected)
trailer X.Auth.User                                → HTTP 200  (bypass)
trailer X-Forwarded-Prefix                         → HTTP 200  (trusted-name trailer passes)
Backend evidence: `TRAILERS: map[X_auth_user:[]]`, `map[X.auth.user:[]]`, `map[X-Forwarded-Prefix:[]]`. The deprecated `underscoreHeadersStrategy = "reject"` behaves identically. `aliasHeadersStrategy = "delete"` (same setup, `delete` in place of `reject`): header `X_Auth_User` / `X.Auth.User` → `200`, backend HEADERS contain neither (deleted, as designed); trailer `X_Auth_User` → `200`, backend `TRAILERS: map[X_auth_user:[]]` — **the trailer form survives `delete`**. **2. Bare-path downstream semantics (name-level).** Same router, backend `h2c://127.0.0.1:8082` running a trailer-merging backend (trailers folded over headers, CGI-style name normalization — the CVE-2026-63379 pattern) that authorizes `/presence` on the merged key and `/value` on `X-Auth-User == "admin"`:
/presence, no trailer (control)                  → 403 DENIED
/presence, trailer X_Auth_User                   → 200 AUTHORIZED      ← presence flip, empty value
/value,    header X-Auth-User: admin + trailer   → merged-user=""       ← legitimate value erased
**3. Real CVE'd component flipped through Traefik — value-level.** Backend: Ubuntu 24.04's `libevent-2.1-7t64` 2.1.12-stable-9ubuntu2 (pre-fix; the merge was fixed only in 2.1.13) plus a small (≈100-line) `evhttp` server that authorizes via `evhttp_find_header(req->input_headers, ...)` (`/prefix` grants admin when `X-Forwarded-Prefix == "admin"`; server source available on request; build: `gcc server.c -levent`). Router adds the retry middleware:
[http.routers.lib]
  entryPoints = ["web"]
  rule = "PathPrefix(`/`)"
  service = "lib"
  middlewares = ["retry-lib"]

[http.middlewares.retry-lib.retry]
  attempts = 2
  status = ["500-599"]

[http.services.lib.loadBalancer.servers]
  [http.services.lib.loadBalancer.servers.s1]
    url = "http://127.0.0.1:8083"
Measured matrix (server log shows the merged `input_headers`): | Request | Result through Traefik | |---|---| | header `X-Forwarded-Prefix: admin` | `403 DENIED` — stripped by `forwardedHeaders` | | trailer `X-Forwarded-Prefix: admin` (chunked, declared; GET) | **`200 ADMIN (prefix=admin)`** — log: `X-Forwarded-Prefix: admin` merged | | trailer `X_Auth_User: attacker-value` (GET) | **`200 AUTHORIZED (presence)`** — log: `X_auth_user: attacker-value` | | same trailer request, retry middleware removed (clean restart) | `403 DENIED` — value dropped, field line omitted; log shows only `Trailer: X_auth_user` | | same trailer request, direct to libevent (no Traefik) | `200 ADMIN (prefix=admin)` — CVE-2026-63379 baseline | The value survives because the retry middleware buffers the body before the proxy clone (mechanism point 2). The same value path holds on h2c outbound (merge backend logs `trailer=map[X-Auth-User:[admin]]` → `200 AUTHORIZED (value=admin)`) and with the `buffering` middleware in place of retry (`/value` trailer → `200 AUTHORIZED (value=admin)`, `/xff` trailer → `200 ADMIN`). **Bait declaration (measured).** Declaring a clean `Trailer: X-Dummy` while additionally sending the undeclared `X_Auth_User: attacker-value` in the trailer section: on the retry-buffered chain the backend receives `TRAILERS: map[X-Dummy:[1] X_auth_user:[attacker-value]]` → `200 AUTHORIZED` (presence policies flip on `X_auth_user`); the zero-declaration control still delivers `map[]`; the bare path delivers only `map[X-Dummy:[]]` (clone precedes the merge). Over HTTP/2 inbound with buffering (`client_h2c` through a retry chain with `retryNonIdempotentMethod`): backend `trailer=map[X_auth_user:[attacker-value]]` → `200 AUTHORIZED (presence)`. **X-Forwarded-For IP-trust (same chain, measured).** Same router and retry middleware, backend `h2c://127.0.0.1:8082` running the merge backend with an added `/xff` route that grants access when the merged `X-Forwarded-For` equals `203.0.113.7` — the classic IP-allowlist pattern:
header  X-Forwarded-For: 203.0.113.7                  → 403 DENIED (xff)
        backend log: merged XFF = "127.0.0.1"  (Traefik stripped the client value and set its own)
trailer X-Forwarded-For: 203.0.113.7  (GET, retry)    → 200 ADMIN (xff)
        backend log: trailer=map[X-Forwarded-For:[203.0.113.7]]
trailer X-Forwarded-For: 203.0.113.7  (POST, retry without retryNonIdempotentMethod → not buffered) → 403 DENIED — merged XFF empty (bare-path value drop)
**4. Framing names and protocols.** Trailer `Content-Length, Host, Connection, Transfer-Encoding` → `400` (Go rejects); `Host, Connection` → `200`, backend `TRAILERS: map[Connection:[] Host:[]]`. HTTP/2 prior-knowledge client with trailer `X_Auth_User` → Traefik → h2c backend: `200`, backend `TRAILERS: map[X_auth_user:[]]` — same name-only outcome as PoC §2. HTTP/3 untested. ### Impact **Kind of vulnerability.** A bypass of Traefik's documented defenses against spoofed trusted names. `reject` promises a `400` and `delete` promises removal for aliasing names; `forwardedHeaders` strips client-supplied `X-Forwarded-*` — and all of it applies to headers only, leaving the trailer channel open, with attacker-chosen values on body-buffering chains. **Who is impacted.** Operators who enabled `delete`/`reject` to close the aliasing spoofing class (the documented mitigation for the CVE-2026-33433/39858/54763 family), and deployments whose backends trust `X-Forwarded-*` names or proxy-set identity headers — including the classic `X-Forwarded-For` IP-trust pattern, where Traefik strips the client's XFF from headers while the trailer form reaches trailer-merging backends. No opt-in option is required for the `X-Forwarded-*` path: the stripping is the default for untrusted clients. The value-level path additionally requires a body-buffering middleware (retry with `status` codes, or `buffering`) — mainstream documented features: the buffering middleware's documentation states that attaching it buffers the request body before forwarding, and the retry middleware's documentation example configures `status = ["400","500-599"]` — though no deployment telemetry is available to quantify their prevalence. **Verified harm scenarios.** 1. *Broken protection contract.* Trailer-form aliasing names are neither rejected nor removed — the documented mitigation has a side door the operator believes is closed. 2. *Presence-based authorization bypass.* Trailer-merging upstreams authorizing on the presence of a trusted identity key flip their decision: `403 → 200 AUTHORIZED` through Traefik on an h2c merge backend (PoC §2) and on the real pre-fix libevent component (PoC §3). 3. *Value-level identity spoofing.* On body-buffering chains the trailer carries the attacker's value: `X-Forwarded-Prefix: admin` delivered through Traefik authorizes as admin on the real CVE'd merge backend, while the identical header form is stripped and denied (PoC §3) — the CVE-2026-63379-class value injection chained through Traefik's own value-preserving middleware behavior. 4. *Legitimate identity value erased.* A trailer-merging upstream folds the empty trailer over the identity header — `X-Auth-User: admin` becomes empty in the merged view (PoC §2). This typically denies rather than grants; its relevance is the erasure primitive and availability of the legitimate identity. 5. *Routing-header name channel.* `Host` and `Connection` trailer fields pass Go's validation and reach the backend name-level (PoC §4); a trailer-merging upstream's virtual-host view is overwritten with an empty value. **Explicitly out of scope (verified).** Value delivery requires a body-buffering middleware in the chain — on bare proxy paths values are dropped (PoC §3); the FastProxy path does not forward trailers; `Content-Length`/`Transfer-Encoding`/`Trailer` trailer fields are rejected with `400`. ### Recommended fix Make the four entrypoint handlers and `forwardedheaders.DeleteXForwardedHeaders` iterate `req.Trailer` as well as `req.Header` — deleting matching trailer entries in `delete` mode and returning `400` in `reject` mode — at the exact place the header filtering already happens. The entrypoint stage sees every declared name (pre-filled before the handler) and covers all of HTTP/2 (undeclared fields are dropped by the stdlib server — mechanism point 3); `reject` returns `400` for those. On HTTP/1.1 buffered chains, names that appear only at body EOF — undeclared fields riding a bait declaration (mechanism point 3) and deleted keys re-added by the blind `mergeSetHeader` merge (mechanism point 4) — bypass the entrypoint stage, so the sanitization must be re-applied after the body's final read for **both** modes and for `DeleteXForwardedHeaders`; at that point the request may already be partially forwarded, so the second stage strips rather than rejects — `reject` deployments get delete-semantics for the late names. HTTP/3 (quic-go) may not pre-fill declared trailer keys before the handler at all (untested); there the post-body stage is the only certain defense. The fix sanitizes only the names the operator's policy targets — it does not drop the trailer channel, so legitimate trailers such as gRPC's `grpc-status` are unaffected.
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/traefik/traefik/v3"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "3.2.0"
            },
            {
              "fixed": "3.7.13"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-88004"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-436",
      "CWE-807"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-09-10T23:04:21Z",
    "nvd_published_at": "2026-09-10T15:17:54Z",
    "severity": "HIGH"
  },
  "details": "## Summary\n\nTraefik\u0027s entrypoint defenses against spoofed trusted header names \u2014 `aliasHeadersStrategy` / `underscoreHeadersStrategy` in `delete` or `reject` mode, and the default `forwardedHeaders` stripping of client-supplied `X-Forwarded-*` \u2014 scan `req.Header` only and never `req.Trailer`. An unauthenticated client can therefore smuggle a sanitized name (an aliasing spelling such as `X_Auth_User`, or a trusted name such as `X-Forwarded-Prefix`) as an HTTP/1.1 chunked trailer or an HTTP/2 trailer: `reject` does not return its documented `400`, `delete` does not remove the name, and Traefik\u0027s reverse proxy forwarded the trailer to the backend \u2014 with an attacker-chosen value whenever a body-buffering middleware (the `retry` middleware with status codes, or the `buffering` middleware) reads the body before the proxy clone. Backends that merge trailers into their header namespace then act on the smuggled name. The fix stops forwarding request trailer values to the backend; the declared trailer names are still forwarded as permitted by RFC 9110 section 6.6.2.\n\nTraefik v2 is not affected: the defect is in the custom reverse proxy introduced in v3 (`pkg/proxy/httputil`), and v2 uses the Go standard library\u0027s `httputil.ReverseProxy`, which does not forward request trailer values to the backend. Affected v3 lines from v3.2.0 through v3.7.12 include the end-of-life v3.2 through v3.6 lines, which will not receive a fix on their own line; the remedy for those users is to upgrade to v3.7.13.\n\n## Patches\n\n- https://github.com/traefik/traefik/releases/tag/v3.7.13\n\n## For more information\n\nIf you have any questions or comments about this advisory, please [open an issue](https://github.com/traefik/traefik/issues).\n\n\u003cdetails\u003e\n\u003csummary\u003eOriginal Description\u003c/summary\u003e\n\n### Summary\n\nTraefik\u0027s entrypoint defenses against spoofed header names \u2014 `aliasHeadersStrategy` / `underscoreHeadersStrategy` in `delete` or `reject` mode, and the `forwardedHeaders` handling that strips client-supplied `X-Forwarded-*` \u2014 scan `req.Header` only and never `req.Trailer`, although the handlers\u0027 own comments promise to cover \"header **and trailer**\". An unauthenticated client can therefore deliver the aliasing name (`X_Auth_User`, `X.Auth.User`) or the trusted name itself (`X-Forwarded-Prefix`, \u2026) as an HTTP/1.1 chunked trailer or an HTTP/2 trailer: `reject` does not return its documented `400`, `delete` does not remove the name, and the trailer form of an `X-Forwarded-*` name passes exactly where the header form is stripped. When a body-buffering middleware is in the chain (retry with `status` codes, or the `buffering` middleware \u2014 both measured), the trailer travels **with an attacker-chosen value**; measured end-to-end against the trailer-merging component Ubuntu 24.04 ships (pre-fix libevent, CVE-2026-63379), the header `X-Forwarded-Prefix: admin` is stripped and denied while the identical name as a trailer is acted upon as admin (`403 \u2192 200`). On bare proxy paths only the trailer name travels (no value), bounding those deployments to name-level effects.\n\n### Details\n\n**Root cause.** All four entrypoint handlers iterate `req.Header` only \u2014 the doc comments promise more than the code does (`pkg/server/server_entrypoint_tcp.go`):\n\n```go\n// removeAliasingHeaders removes any request header and trailer whose name contains a character\n// which is neither a letter, a digit, nor a dash, as such a name aliases another header name.\nfunc removeAliasingHeaders(h http.Handler) http.Handler {\n\treturn http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {\n\t\tfor key := range req.Header {          // \u2190 req.Trailer is never scanned\n\t\t\tif isAliasingHeaderName(key) {\n\t\t\t\tdelete(req.Header, key)\n\t\t\t}\n\t\t}\n\t\th.ServeHTTP(rw, req)\n\t})\n}\n```\n\n`rejectAliasingHeaders`, `removeHeadersWithUnderscores` and `rejectHeadersWithUnderscores` share the identical structure (the `reject` variants return `400` from the same loop). The sibling sanitization `forwardedheaders.DeleteXForwardedHeaders` (`pkg/middlewares/forwardedheaders/forwarded_header.go`) also scans `req.Header` only, so the trusted `X-Forwarded-*` names whose header form Traefik strips for untrusted clients \u2014 the managed `XHeadersSet`, which includes `X-Forwarded-Prefix` and `X-Forwarded-For` \u2014 survive in trailer form. Go\u0027s HTTP server populates `req.Trailer` from chunked/HTTP/2 trailers, and Traefik\u0027s proxy layer forwards those entries, bypassing the sanitization above.\n\n**Contract provenance.** The \"header and trailer\" wording is in the original introducing diffs \u2014 `108a52644` (underscoreHeadersStrategy) and `0331801c` (aliasHeadersStrategy) \u2014 and is unchanged in `master` (full diff excerpts available on request). The option began as `allowHeadersWithUnderscores: false` (per the CVE-2026-54763 record) before becoming `underscoreHeadersStrategy` and then `aliasHeadersStrategy`. The user-facing documentation describes only \"request headers\".\n\n**Mechanism (why names survive, and when values do too).**\n\n1. *Name pre-fill at parse time.* The client\u0027s `Trailer: X_Auth_User` declaration makes Go\u0027s server move the declared keys into `req.Trailer` with nil values before the handler runs (`net/http/transfer.go`, `fixTrailer`); HTTP/2 does the same from the `trailer:` field in the initial HEADERS (\"Setup Trailers\", `net/http/internal/httpcommon/httpcommon.go`). The entrypoint handlers therefore cannot see the trailer name, but the proxy forwards it. Trailer keys are canonicalized with `textproto.CanonicalMIMEHeaderKey`, which treats dashes \u2014 not underscores \u2014 as case separators: the aliasing spelling survives canonicalization as e.g. `X_auth_user` (visible in the backend dumps in PoC \u00a71) and remains detectable by `isAliasingHeaderName`, so the fix does not depend on the client\u0027s original spelling.\n2. *Value survival depends on who reads the body first.* Trailer values are appended to `req.Trailer` only while the body is consumed (`readTrailer` / `copyTrailersToHandlerRequest`). On the bare path the reverse proxy calls `Request.Clone` at handler start, before any body read, so the clone captures nil values \u2014 on HTTP/1.1 the trailer field line is then omitted entirely (`net/http/header.go`, `Header.writeSubset` writes one line per value), and h2c delivers only the empty key. When a body-buffering middleware runs first, the order reverses: the retry middleware with `status` codes buffers the body via `mirror.NewReusableRequest` \u2192 `io.ReadAll(req.Body)` (`pkg/middlewares/retry/retry.go`, `pkg/server/service/loadbalancer/mirror/mirror.go`), the values are populated before `http.Request.Clone`, and they travel to the backend. Buffering triggers for idempotent methods with `status` alone; POST additionally requires `retryNonIdempotentMethod` (both measured). Retry and buffering are the two measured paths; the mirroring and failover services use the same `mirror.NewReusableRequest` helper (`pkg/server/service/loadbalancer/mirror/mirror.go`, `failover/failover.go` when `errors.status` is configured) and share its behavior (not measured). The `buffering` middleware drains the body eagerly before the proxy too: `pkg/middlewares/buffering/buffering.go` \u2192 oxy\u0027s `multibuf.New` \u2192 `ioutil.ReadAll` (github.com/mailgun/multibuf `buffer.go`; unset limits fall back to 1 MB `DefaultMemBytes`) \u2014 measured value-preserving with default limits.\n3. *Undeclared trailers: transit depends on whether anything else was declared (measured).* On HTTP/2 the standard library server copies only pre-declared trailers (\"Only copy it over it was pre-declared\", `net/http/internal/http2/server.go`) \u2014 undeclared fields never appear. On HTTP/1.1 `readTrailer` parses the entire trailer section with no declaration filter, and `mergeSetHeader` either **rebinds** the map when nil (`*dst = src`) or blindly merges when non-nil (point 4). The rebind is why zero-declaration requests lose undeclared fields at Traefik\u0027s observability `req.WithContext` shallow copy (`pkg/middlewares/observability/observability.go`, `entrypoint.go`) \u2014 measured: they never leave the entrypoint even on buffered chains. But a **bait declaration** (any clean name, e.g. `X-Dummy`) keeps the map non-nil, and the blind merge then writes the undeclared field into the shared map at body EOF \u2014 measured on the retry-buffered chain: the backend receives `map[X-Dummy:[1] X_auth_user:[attacker-value]]` and presence-based policies flip; the bare path is unaffected and delivers only `map[X-Dummy:[]]`.\n4. *Delete-mode stickiness depends on the merge semantics (measured).* `readTrailer` merges parsed trailer fields via `mergeSetHeader`, whose non-nil branch is a blind `maps.Copy` (`net/http/transfer.go`) \u2014 a key deleted by a handler is re-added **with its value** at body EOF. Measured on a bare Go server (`delete(r.Trailer, \"X_auth_user\")` before draining the body): HTTP/1.1 \u2014 `map[X_auth_user:[]]` \u2192 `map[X_auth_user:[attacker-value]]` (re-added); HTTP/2 \u2014 `map[X_auth_user:[]]` \u2192 `map[]` (stays deleted: `copyTrailersToHandlerRequest` checks the live map).\n\n**Deliberate trailer-forwarding behavior (regression tests).** Traefik deliberately does not forward request trailers on the bare proxy chain, locked by the regression tests `pkg/proxy/httputil/trailer_test.go` and `pkg/proxy/fast/trailer_test.go` (added `86b5642f`, 2026-06-25; extended `d427dccf`, 2026-06-29): \"trailers arrive after the body, once routing and security decisions have already been made, so forwarding them could raise security concerns in Traefik.\" The measured buffered-chain value survival (mechanism point 2) defeats exactly that locked invariant \u2014 the tests exercise only the bare chain \u2014 and the name-level h2c forwarding (empty keys) passes the tests\u0027 assertion (`Header.Get` is empty whether the key is absent or empty-valued): neither regression test catches this finding. The value-level path thus bypasses a deliberate, test-locked security invariant.\n\n**Preconditions.**\n\n1. An entrypoint whose sanitization is relied upon: `aliasHeadersStrategy` / `underscoreHeadersStrategy` set to `delete` or `reject`, or the default `forwardedHeaders` stripping of `X-Forwarded-*` for untrusted clients.\n2. A request carrying the name as a declared trailer (HTTP/1.1 chunked, or HTTP/2), or \u2014 on HTTP/1.1 buffered chains only \u2014 as an undeclared trailer field riding a bait declaration (mechanism point 3).\n3. For downstream impact: a backend that merges trailers into its header namespace (pre-fix libevent CVE-2026-63379 \u2014 still what Ubuntu 24.04 ships \u2014, pre-fix blaze CVE-2026-73495, or custom code) or consumes trailer fields in a trust decision.\n4. For the value-level path: the retry middleware with `status` codes, the `buffering` middleware, or another body-buffering middleware, in the chain.\n\n**Precedent and scope.** This is the next variant of Traefik\u0027s own aliasing family \u2014 CVE-2026-33433 (GHSA-qr99-7898-vr7c), CVE-2026-39858 (GHSA-5m6w-wvh7-57vm), CVE-2026-54763 (GHSA-x677-9fxg-v5c5) \u2014 and Traefik\u0027s Security Decisions state the in-scope line: \"a spelling that survives the entrypoint sanitisation and still reaches the backend as the trusted name\". The trailer spelling is precisely that. The downstream merge class is cross-ecosystem: libevent CVE-2026-63379 (run live in PoC \u00a73) and blaze/http4s CVE-2026-73495 (GHSA-46q4-43ph-c6fr, fixed `ef3e666`).\n\n**Boundaries (measured).** Declaring `Content-Length`, `Transfer-Encoding` or `Trailer` as trailer fields is rejected with `400` by Go\u0027s server; `Host` and `Connection` pass through name-level. The FastProxy forwarding mode (opt-in `[experimental] fastProxy`) does not forward trailers; the default reverse-proxy path for `http://` backends does (PoC \u00a73). HTTP/3 (quic-go) trailer semantics are untested. Undeclared trailers: HTTP/2 drops them entirely; on HTTP/1.1 they transit only via a bait declaration on buffered chains (mechanism point 3).\n\n### PoC\n\nVerified against a source-built Traefik (`master` @ `237f13c6`, built with **Go 1.27.0**; all harness backends built with Go 1.27.0 \u2014 the trailer behaviors cited in Details are version-sensitive `net/http` internals). Complete harness (clients, backends, configs, logs) available on request; the raw chunked requests below are HTTP/1.1 and reproducible with `nc`/`python`.\n\n**1. Core bypass (`aliasHeadersStrategy = reject`).** Static config:\n\n```toml\n[entryPoints.web]\n  address = \":8090\"\n  [entryPoints.web.http]\n    aliasHeadersStrategy = \"reject\"\n\n[providers.file]\n  filename = \"dynamic.toml\"\n  watch = true\n```\n\n`dynamic.toml`: router `PathPrefix(`/`)` \u2192 service \u2192 `h2c://127.0.0.1:8081` (a Go echo backend that drains the body and prints `r.Trailer`). Requests (CRLF line endings; `5`/`0` are chunk sizes):\n\n```\nPOST / HTTP/1.1\nHost: 127.0.0.1:8090\nConnection: close\nTransfer-Encoding: chunked\nTrailer: X_Auth_User\n\n5\nhello\n0\nX_Auth_User: attacker-value\n\n```\n\nResults:\n\n```\nheader  X_Auth_User   (curl -H \"X_Auth_User: x\")  \u2192 HTTP 400  (rejected, as designed)\ntrailer X_Auth_User   (request above)             \u2192 HTTP 200  (bypass: not rejected)\ntrailer X.Auth.User                                \u2192 HTTP 200  (bypass)\ntrailer X-Forwarded-Prefix                         \u2192 HTTP 200  (trusted-name trailer passes)\n```\n\nBackend evidence: `TRAILERS: map[X_auth_user:[]]`, `map[X.auth.user:[]]`, `map[X-Forwarded-Prefix:[]]`. The deprecated `underscoreHeadersStrategy = \"reject\"` behaves identically.\n\n`aliasHeadersStrategy = \"delete\"` (same setup, `delete` in place of `reject`): header `X_Auth_User` / `X.Auth.User` \u2192 `200`, backend HEADERS contain neither (deleted, as designed); trailer `X_Auth_User` \u2192 `200`, backend `TRAILERS: map[X_auth_user:[]]` \u2014 **the trailer form survives `delete`**.\n\n**2. Bare-path downstream semantics (name-level).** Same router, backend `h2c://127.0.0.1:8082` running a trailer-merging backend (trailers folded over headers, CGI-style name normalization \u2014 the CVE-2026-63379 pattern) that authorizes `/presence` on the merged key and `/value` on `X-Auth-User == \"admin\"`:\n\n```\n/presence, no trailer (control)                  \u2192 403 DENIED\n/presence, trailer X_Auth_User                   \u2192 200 AUTHORIZED      \u2190 presence flip, empty value\n/value,    header X-Auth-User: admin + trailer   \u2192 merged-user=\"\"       \u2190 legitimate value erased\n```\n\n**3. Real CVE\u0027d component flipped through Traefik \u2014 value-level.** Backend: Ubuntu 24.04\u0027s `libevent-2.1-7t64` 2.1.12-stable-9ubuntu2 (pre-fix; the merge was fixed only in 2.1.13) plus a small (\u2248100-line) `evhttp` server that authorizes via `evhttp_find_header(req-\u003einput_headers, ...)` (`/prefix` grants admin when `X-Forwarded-Prefix == \"admin\"`; server source available on request; build: `gcc server.c -levent`). Router adds the retry middleware:\n\n```toml\n[http.routers.lib]\n  entryPoints = [\"web\"]\n  rule = \"PathPrefix(`/`)\"\n  service = \"lib\"\n  middlewares = [\"retry-lib\"]\n\n[http.middlewares.retry-lib.retry]\n  attempts = 2\n  status = [\"500-599\"]\n\n[http.services.lib.loadBalancer.servers]\n  [http.services.lib.loadBalancer.servers.s1]\n    url = \"http://127.0.0.1:8083\"\n```\n\nMeasured matrix (server log shows the merged `input_headers`):\n\n| Request | Result through Traefik |\n|---|---|\n| header `X-Forwarded-Prefix: admin` | `403 DENIED` \u2014 stripped by `forwardedHeaders` |\n| trailer `X-Forwarded-Prefix: admin` (chunked, declared; GET) | **`200 ADMIN (prefix=admin)`** \u2014 log: `X-Forwarded-Prefix: admin` merged |\n| trailer `X_Auth_User: attacker-value` (GET) | **`200 AUTHORIZED (presence)`** \u2014 log: `X_auth_user: attacker-value` |\n| same trailer request, retry middleware removed (clean restart) | `403 DENIED` \u2014 value dropped, field line omitted; log shows only `Trailer: X_auth_user` |\n| same trailer request, direct to libevent (no Traefik) | `200 ADMIN (prefix=admin)` \u2014 CVE-2026-63379 baseline |\n\nThe value survives because the retry middleware buffers the body before the proxy clone (mechanism point 2). The same value path holds on h2c outbound (merge backend logs `trailer=map[X-Auth-User:[admin]]` \u2192 `200 AUTHORIZED (value=admin)`) and with the `buffering` middleware in place of retry (`/value` trailer \u2192 `200 AUTHORIZED (value=admin)`, `/xff` trailer \u2192 `200 ADMIN`).\n\n**Bait declaration (measured).** Declaring a clean `Trailer: X-Dummy` while additionally sending the undeclared `X_Auth_User: attacker-value` in the trailer section: on the retry-buffered chain the backend receives `TRAILERS: map[X-Dummy:[1] X_auth_user:[attacker-value]]` \u2192 `200 AUTHORIZED` (presence policies flip on `X_auth_user`); the zero-declaration control still delivers `map[]`; the bare path delivers only `map[X-Dummy:[]]` (clone precedes the merge). Over HTTP/2 inbound with buffering (`client_h2c` through a retry chain with `retryNonIdempotentMethod`): backend `trailer=map[X_auth_user:[attacker-value]]` \u2192 `200 AUTHORIZED (presence)`.\n\n**X-Forwarded-For IP-trust (same chain, measured).** Same router and retry middleware, backend `h2c://127.0.0.1:8082` running the merge backend with an added `/xff` route that grants access when the merged `X-Forwarded-For` equals `203.0.113.7` \u2014 the classic IP-allowlist pattern:\n\n```\nheader  X-Forwarded-For: 203.0.113.7                  \u2192 403 DENIED (xff)\n        backend log: merged XFF = \"127.0.0.1\"  (Traefik stripped the client value and set its own)\ntrailer X-Forwarded-For: 203.0.113.7  (GET, retry)    \u2192 200 ADMIN (xff)\n        backend log: trailer=map[X-Forwarded-For:[203.0.113.7]]\ntrailer X-Forwarded-For: 203.0.113.7  (POST, retry without retryNonIdempotentMethod \u2192 not buffered) \u2192 403 DENIED \u2014 merged XFF empty (bare-path value drop)\n```\n\n**4. Framing names and protocols.** Trailer `Content-Length, Host, Connection, Transfer-Encoding` \u2192 `400` (Go rejects); `Host, Connection` \u2192 `200`, backend `TRAILERS: map[Connection:[] Host:[]]`. HTTP/2 prior-knowledge client with trailer `X_Auth_User` \u2192 Traefik \u2192 h2c backend: `200`, backend `TRAILERS: map[X_auth_user:[]]` \u2014 same name-only outcome as PoC \u00a72. HTTP/3 untested.\n\n### Impact\n\n**Kind of vulnerability.** A bypass of Traefik\u0027s documented defenses against spoofed trusted names. `reject` promises a `400` and `delete` promises removal for aliasing names; `forwardedHeaders` strips client-supplied `X-Forwarded-*` \u2014 and all of it applies to headers only, leaving the trailer channel open, with attacker-chosen values on body-buffering chains.\n\n**Who is impacted.** Operators who enabled `delete`/`reject` to close the aliasing spoofing class (the documented mitigation for the CVE-2026-33433/39858/54763 family), and deployments whose backends trust `X-Forwarded-*` names or proxy-set identity headers \u2014 including the classic `X-Forwarded-For` IP-trust pattern, where Traefik strips the client\u0027s XFF from headers while the trailer form reaches trailer-merging backends. No opt-in option is required for the `X-Forwarded-*` path: the stripping is the default for untrusted clients. The value-level path additionally requires a body-buffering middleware (retry with `status` codes, or `buffering`) \u2014 mainstream documented features: the buffering middleware\u0027s documentation states that attaching it buffers the request body before forwarding, and the retry middleware\u0027s documentation example configures `status = [\"400\",\"500-599\"]` \u2014 though no deployment telemetry is available to quantify their prevalence.\n\n**Verified harm scenarios.**\n\n1. *Broken protection contract.* Trailer-form aliasing names are neither rejected nor removed \u2014 the documented mitigation has a side door the operator believes is closed.\n2. *Presence-based authorization bypass.* Trailer-merging upstreams authorizing on the presence of a trusted identity key flip their decision: `403 \u2192 200 AUTHORIZED` through Traefik on an h2c merge backend (PoC \u00a72) and on the real pre-fix libevent component (PoC \u00a73).\n3. *Value-level identity spoofing.* On body-buffering chains the trailer carries the attacker\u0027s value: `X-Forwarded-Prefix: admin` delivered through Traefik authorizes as admin on the real CVE\u0027d merge backend, while the identical header form is stripped and denied (PoC \u00a73) \u2014 the CVE-2026-63379-class value injection chained through Traefik\u0027s own value-preserving middleware behavior.\n4. *Legitimate identity value erased.* A trailer-merging upstream folds the empty trailer over the identity header \u2014 `X-Auth-User: admin` becomes empty in the merged view (PoC \u00a72). This typically denies rather than grants; its relevance is the erasure primitive and availability of the legitimate identity.\n5. *Routing-header name channel.* `Host` and `Connection` trailer fields pass Go\u0027s validation and reach the backend name-level (PoC \u00a74); a trailer-merging upstream\u0027s virtual-host view is overwritten with an empty value.\n\n**Explicitly out of scope (verified).** Value delivery requires a body-buffering middleware in the chain \u2014 on bare proxy paths values are dropped (PoC \u00a73); the FastProxy path does not forward trailers; `Content-Length`/`Transfer-Encoding`/`Trailer` trailer fields are rejected with `400`.\n\n### Recommended fix\n\nMake the four entrypoint handlers and `forwardedheaders.DeleteXForwardedHeaders` iterate `req.Trailer` as well as `req.Header` \u2014 deleting matching trailer entries in `delete` mode and returning `400` in `reject` mode \u2014 at the exact place the header filtering already happens. The entrypoint stage sees every declared name (pre-filled before the handler) and covers all of HTTP/2 (undeclared fields are dropped by the stdlib server \u2014 mechanism point 3); `reject` returns `400` for those. On HTTP/1.1 buffered chains, names that appear only at body EOF \u2014 undeclared fields riding a bait declaration (mechanism point 3) and deleted keys re-added by the blind `mergeSetHeader` merge (mechanism point 4) \u2014 bypass the entrypoint stage, so the sanitization must be re-applied after the body\u0027s final read for **both** modes and for `DeleteXForwardedHeaders`; at that point the request may already be partially forwarded, so the second stage strips rather than rejects \u2014 `reject` deployments get delete-semantics for the late names. HTTP/3 (quic-go) may not pre-fill declared trailer keys before the handler at all (untested); there the post-body stage is the only certain defense. The fix sanitizes only the names the operator\u0027s policy targets \u2014 it does not drop the trailer channel, so legitimate trailers such as gRPC\u0027s `grpc-status` are unaffected.\n\n\u003c/details\u003e\n\n---",
  "id": "GHSA-v67p-phpq-fc8x",
  "modified": "2026-09-10T23:04:21Z",
  "published": "2026-09-10T23:04:21Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/traefik/traefik/security/advisories/GHSA-v67p-phpq-fc8x"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-88004"
    },
    {
      "type": "WEB",
      "url": "https://github.com/traefik/traefik/pull/13822"
    },
    {
      "type": "WEB",
      "url": "https://github.com/traefik/traefik/commit/55bbda4f65e0f9c533c870983a767a7081126db7"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/traefik/traefik"
    },
    {
      "type": "WEB",
      "url": "https://github.com/traefik/traefik/releases/tag/v3.7.13"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:H/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:H/SI:H/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Traefik entrypoint header-name sanitization bypassed via request trailers"
}

GHSA-V8P8-W9Q2-Q67J

Vulnerability from github – Published: 2025-01-14 15:30 – Updated: 2025-01-14 15:30
VLAI
Details

An improper neutralization of crlf sequences in http headers ('http response splitting') in Fortinet FortiOS 7.2.0 through 7.6.0, FortiProxy 7.2.0 through 7.4.5 allows attacker to execute unauthorized code or commands via crafted HTTP header.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2024-54021"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-113",
      "CWE-436"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2025-01-14T14:15:34Z",
    "severity": "MODERATE"
  },
  "details": "An improper neutralization of crlf sequences in http headers (\u0027http response splitting\u0027) in Fortinet FortiOS 7.2.0 through 7.6.0, FortiProxy 7.2.0 through 7.4.5 allows attacker to execute unauthorized code or commands via crafted HTTP header.",
  "id": "GHSA-v8p8-w9q2-q67j",
  "modified": "2025-01-14T15:30:54Z",
  "published": "2025-01-14T15:30:54Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-54021"
    },
    {
      "type": "WEB",
      "url": "https://fortiguard.fortinet.com/psirt/FG-IR-24-282"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:L",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-V9WW-2J6R-98Q6

Vulnerability from github – Published: 2026-04-16 22:28 – Updated: 2026-04-16 22:28
VLAI
Summary
@fastify/middie vulnerable to middleware bypass via deprecated ignoreDuplicateSlashes option
Details

Impact

@fastify/middie v9.3.1 and earlier does not read the deprecated (but still functional) top-level ignoreDuplicateSlashes option, only reading from routerOptions. This creates a normalization gap: Fastify's router normalizes duplicate slashes but middie does not, allowing middleware bypass via URLs with duplicate leading slashes (e.g., //admin/secret).

This only affects applications using the deprecated top-level configuration style (fastify({ ignoreDuplicateSlashes: true })). Applications using routerOptions: { ignoreDuplicateSlashes: true } are not affected.

This is distinct from GHSA-8p85-9qpw-fwgw (CVE-2026-2880), which was patched in v9.2.0.

Patches

Upgrade to @fastify/middie >= 9.3.2.

Workarounds

Migrate from deprecated top-level ignoreDuplicateSlashes: true to routerOptions: { ignoreDuplicateSlashes: true }.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 9.3.1"
      },
      "package": {
        "ecosystem": "npm",
        "name": "@fastify/middie"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "9.3.2"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-33804"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-436"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-04-16T22:28:54Z",
    "nvd_published_at": "2026-04-16T15:17:34Z",
    "severity": "HIGH"
  },
  "details": "### Impact\n\n`@fastify/middie` v9.3.1 and earlier does not read the deprecated (but still functional) top-level `ignoreDuplicateSlashes` option, only reading from `routerOptions`. This creates a normalization gap: Fastify\u0027s router normalizes duplicate slashes but middie does not, allowing middleware bypass via URLs with duplicate leading slashes (e.g., `//admin/secret`).\n\nThis only affects applications using the deprecated top-level configuration style (`fastify({ ignoreDuplicateSlashes: true })`). Applications using `routerOptions: { ignoreDuplicateSlashes: true }` are not affected.\n\nThis is distinct from [GHSA-8p85-9qpw-fwgw](https://github.com/fastify/middie/security/advisories/GHSA-8p85-9qpw-fwgw) (CVE-2026-2880), which was patched in v9.2.0.\n\n### Patches\n\nUpgrade to `@fastify/middie` \u003e= 9.3.2.\n\n### Workarounds\n\nMigrate from deprecated top-level `ignoreDuplicateSlashes: true` to `routerOptions: { ignoreDuplicateSlashes: true }`.",
  "id": "GHSA-v9ww-2j6r-98q6",
  "modified": "2026-04-16T22:28:54Z",
  "published": "2026-04-16T22:28:54Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/fastify/middie/security/advisories/GHSA-v9ww-2j6r-98q6"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-33804"
    },
    {
      "type": "WEB",
      "url": "https://cna.openjsf.org/security-advisories.html"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/fastify/middie"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "@fastify/middie vulnerable to middleware bypass via deprecated ignoreDuplicateSlashes option"
}

GHSA-VC47-6RQG-C7F5

Vulnerability from github – Published: 2022-11-19 00:30 – Updated: 2025-11-04 19:37
VLAI
Summary
HTTP response splitting in CGI
Details

Ruby gem cgi.rb prior to versions 0.3.5, 0.2.2 and 0.1.0.2 allow HTTP header injection. If a CGI application using the CGI library inserts untrusted input into the HTTP response header, an attacker can exploit it to insert a newline character to split a header, and inject malicious content to deceive clients. This issue has been patched in versions 0.3.5, 0.2.2 and 0.1.0.2.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "RubyGems",
        "name": "cgi"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0.3.0"
            },
            {
              "fixed": "0.3.5"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "RubyGems",
        "name": "cgi"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0.2.0"
            },
            {
              "fixed": "0.2.2"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "RubyGems",
        "name": "cgi"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.1.0.2"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2021-33621"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-436",
      "CWE-74"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2022-11-24T01:59:37Z",
    "nvd_published_at": "2022-11-18T23:15:00Z",
    "severity": "HIGH"
  },
  "details": "Ruby gem cgi.rb prior to versions 0.3.5, 0.2.2 and 0.1.0.2 allow HTTP header injection. If a CGI application using the CGI library inserts untrusted input into the HTTP response header, an attacker can exploit it to insert a newline character to split a header, and inject malicious content to deceive clients. This issue has been patched in versions 0.3.5, 0.2.2 and 0.1.0.2.",
  "id": "GHSA-vc47-6rqg-c7f5",
  "modified": "2025-11-04T19:37:14Z",
  "published": "2022-11-19T00:30:55Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-33621"
    },
    {
      "type": "WEB",
      "url": "https://hackerone.com/reports/1204695"
    },
    {
      "type": "WEB",
      "url": "https://github.com/rubysec/ruby-advisory-db/blob/master/gems/cgi/CVE-2021-33621.yml"
    },
    {
      "type": "WEB",
      "url": "https://lists.debian.org/debian-lts-announce/2023/06/msg00012.html"
    },
    {
      "type": "WEB",
      "url": "https://lists.debian.org/debian-lts-announce/2024/09/msg00000.html"
    },
    {
      "type": "WEB",
      "url": "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/DQR7LWED6VAPD5ATYOBZIGJQPCUBRJBX"
    },
    {
      "type": "WEB",
      "url": "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/THVTYHHEOVLQFCFHWURZYO7PVUPBHRZD"
    },
    {
      "type": "WEB",
      "url": "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/YACE6ORF2QBXXBK2V2CM36D7TZMEJVAS"
    },
    {
      "type": "WEB",
      "url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/DQR7LWED6VAPD5ATYOBZIGJQPCUBRJBX"
    },
    {
      "type": "WEB",
      "url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/THVTYHHEOVLQFCFHWURZYO7PVUPBHRZD"
    },
    {
      "type": "WEB",
      "url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/YACE6ORF2QBXXBK2V2CM36D7TZMEJVAS"
    },
    {
      "type": "WEB",
      "url": "https://security.gentoo.org/glsa/202401-27"
    },
    {
      "type": "WEB",
      "url": "https://security.netapp.com/advisory/ntap-20221228-0004"
    },
    {
      "type": "WEB",
      "url": "https://www.ruby-lang.org/en/news/2022/11/22/http-response-splitting-in-cgi-cve-2021-33621"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "HTTP response splitting in CGI"
}

GHSA-VFFW-93WF-4J4Q

Vulnerability from github – Published: 2026-06-15 20:20 – Updated: 2026-07-15 22:06
VLAI
Summary
python-multipart: Content-Disposition parameter smuggling via RFC 2231/5987 extended parameters
Details

Summary

parse_options_header parsed Content-Disposition (and Content-Type) headers with email.message.Message, which transparently applies RFC 2231/5987 decoding. The extended parameter syntax (filename*=charset'lang'value, name*=..., and the filename*0/filename*1 continuation form) is decoded and surfaced under the bare filename/name key, and overrides the plain parameter when both are present. RFC 7578 §4.2 explicitly forbids the filename* form in multipart/form-data.

Components that follow RFC 7578, or that do not implement RFC 2231/5987 decoding for multipart/form-data (WAFs, proxies, gateways), may interpret such a header differently. An attacker can exploit that difference to smuggle a different field name or filename past an upstream inspector to the backend.

Details

Given both a plain and an extended parameter, the extended value won. For example:

Content-Disposition: form-data; name="comment"; name*=utf-8''role

An inspector following RFC 7578 sees the field comment, while the returned value was name=role. The same applies to filenames:

Content-Disposition: form-data; name="upload"; filename="safe.txt"; filename*=utf-8''evil.php

The inspector sees safe.txt, while the returned value was filename=evil.php. Continuation parameters (filename*0, filename*1, and so on) were likewise reassembled into a filename invisible to a plain filename= match, and percent encoded sequences in the extended value were decoded (so ..%2F, %00, and similar appeared in the returned filename).

This affects the high level parse_options_header, FormParser, create_form_parser, and parse_form APIs, and reaches Starlette/FastAPI through request.form(), where the smuggled value is exposed as the form field name or UploadFile.filename.

Impact

This is an interpretation conflict (CWE-436) with other multipart/form-data parsers. An attacker able to submit multipart/form-data can present a different field name or filename to an upstream body inspecting component than the one delivered to the application. Concrete consequences depend on how the application uses these values, and may include bypassing a field name or filename based access/upload control, or, for an application that builds filesystem paths from the parsed filename without sanitization, path traversal via decoded ..%2F sequences. Decoded control bytes such as %00 can likewise cause confusion between an upstream validator and the backend. The File class applies os.path.basename, so file writing through it is not directly affected.

Mitigation

Upgrade to python-multipart 0.0.30 or later, which ignores RFC 2231/5987 extended parameters (name*, filename*, and their continuations) so the plain name/filename parameter remains authoritative. RFC 7578 §4.2 forbids filename* for multipart/form-data; name* and the continuation forms are dropped for the same reason, since they are not valid multipart/form-data parameters either.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "python-multipart"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.0.30"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-53537"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-20",
      "CWE-436"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-06-15T20:20:51Z",
    "nvd_published_at": "2026-06-22T18:16:44Z",
    "severity": "LOW"
  },
  "details": "### Summary\n\n`parse_options_header` parsed `Content-Disposition` (and `Content-Type`) headers with [`email.message.Message`](https://docs.python.org/3/library/email.compat32-message.html#email.message.Message), which transparently applies [RFC 2231](https://datatracker.ietf.org/doc/html/rfc2231)/[5987](https://datatracker.ietf.org/doc/html/rfc5987) decoding. The extended parameter syntax (`filename*=charset\u0027lang\u0027value`, `name*=...`, and the `filename*0`/`filename*1` continuation form) is decoded and surfaced under the bare `filename`/`name` key, and overrides the plain parameter when both are present. [RFC 7578 \u00a74.2](https://datatracker.ietf.org/doc/html/rfc7578#section-4.2) explicitly forbids the `filename*` form in `multipart/form-data`.\n\nComponents that follow RFC 7578, or that do not implement RFC 2231/5987 decoding for `multipart/form-data` (WAFs, proxies, gateways), may interpret such a header differently. An attacker can exploit that difference to smuggle a different field name or filename past an upstream inspector to the backend.\n\n### Details\n\nGiven both a plain and an extended parameter, the extended value won. For example:\n\n```\nContent-Disposition: form-data; name=\"comment\"; name*=utf-8\u0027\u0027role\n```\n\nAn inspector following RFC 7578 sees the field `comment`, while the returned value was `name=role`. The same applies to filenames:\n\n```\nContent-Disposition: form-data; name=\"upload\"; filename=\"safe.txt\"; filename*=utf-8\u0027\u0027evil.php\n```\n\nThe inspector sees `safe.txt`, while the returned value was `filename=evil.php`. Continuation parameters (`filename*0`, `filename*1`, and so on) were likewise reassembled into a `filename` invisible to a plain `filename=` match, and percent encoded sequences in the extended value were decoded (so `..%2F`, `%00`, and similar appeared in the returned filename).\n\nThis affects the high level `parse_options_header`, `FormParser`, `create_form_parser`, and `parse_form` APIs, and reaches Starlette/FastAPI through `request.form()`, where the smuggled value is exposed as the form field name or [`UploadFile.filename`](https://www.starlette.io/requests/#request-files).\n\n### Impact\n\nThis is an interpretation conflict ([CWE-436](https://cwe.mitre.org/data/definitions/436.html)) with other `multipart/form-data` parsers. An attacker able to submit `multipart/form-data` can present a different field name or filename to an upstream body inspecting component than the one delivered to the application. Concrete consequences depend on how the application uses these values, and may include bypassing a field name or filename based access/upload control, or, for an application that builds filesystem paths from the parsed filename without sanitization, path traversal via decoded `..%2F` sequences. Decoded control bytes such as `%00` can likewise cause confusion between an upstream validator and the backend. The `File` class applies `os.path.basename`, so file writing through it is not directly affected.\n\n### Mitigation\n\nUpgrade to `python-multipart` `0.0.30` or later, which ignores RFC 2231/5987 extended parameters (`name*`, `filename*`, and their continuations) so the plain `name`/`filename` parameter remains authoritative. RFC 7578 \u00a74.2 forbids `filename*` for `multipart/form-data`; `name*` and the continuation forms are dropped for the same reason, since they are not valid `multipart/form-data` parameters either.",
  "id": "GHSA-vffw-93wf-4j4q",
  "modified": "2026-07-15T22:06:51Z",
  "published": "2026-06-15T20:20:51Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/Kludex/python-multipart/security/advisories/GHSA-vffw-93wf-4j4q"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-53537"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/Kludex/python-multipart"
    },
    {
      "type": "ADVISORY",
      "url": "https://github.com/advisories/GHSA-vffw-93wf-4j4q"
    },
    {
      "type": "WEB",
      "url": "https://github.com/pypa/advisory-database/blob/main/vulns/python-multipart/PYSEC-2026-3041.yaml"
    },
    {
      "type": "WEB",
      "url": "https://pypi.org/project/python-multipart"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "python-multipart: Content-Disposition parameter smuggling via RFC 2231/5987 extended parameters"
}

GHSA-VFMV-JFC5-PJJW

Vulnerability from github – Published: 2024-03-25 19:40 – Updated: 2024-03-27 13:00
VLAI
Summary
CarrierWave content-Type allowlist bypass vulnerability which possibly leads to XSS remained
Details

Impact

The vulnerability CVE-2023-49090 wasn't fully addressed.

This vulnerability is caused by the fact that when uploading to object storage, including Amazon S3, it is possible to set a Content-Type value that is interpreted by browsers to be different from what's allowed by content_type_allowlist, by providing multiple values separated by commas.

This bypassed value can be used to cause XSS.

Patches

Upgrade to 3.0.7 or 2.2.6.

Workarounds

Use the following monkey patch to let CarrierWave parse the Content-type by using Marcel::MimeType.for.

# For CarrierWave 3.x
CarrierWave::SanitizedFile.class_eval do
  def declared_content_type
    @declared_content_type ||
      if @file.respond_to?(:content_type) && @file.content_type
        Marcel::MimeType.for(declared_type: @file.content_type.to_s.chomp)
      end
  end
end
# For CarrierWave 2.x
CarrierWave::SanitizedFile.class_eval do
  def existing_content_type
    if @file.respond_to?(:content_type) && @file.content_type
      Marcel::MimeType.for(declared_type: @file.content_type.to_s.chomp)
    end
  end
end

References

OWASP - File Upload Cheat Sheet

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "RubyGems",
        "name": "carrierwave"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "3.0.0"
            },
            {
              "fixed": "3.0.7"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "RubyGems",
        "name": "carrierwave"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "2.2.6"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2024-29034"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-436",
      "CWE-79"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2024-03-25T19:40:36Z",
    "nvd_published_at": "2024-03-24T20:15:07Z",
    "severity": "MODERATE"
  },
  "details": "### Impact\nThe vulnerability [CVE-2023-49090](https://github.com/carrierwaveuploader/carrierwave/security/advisories/GHSA-gxhx-g4fq-49hj) wasn\u0027t fully addressed.\n\nThis vulnerability is caused by the fact that when uploading to object storage, including Amazon S3, it is possible to set a Content-Type value that is interpreted by browsers to be different from what\u0027s allowed by `content_type_allowlist`, by providing multiple values separated by commas.\n\nThis bypassed value can be used to cause XSS.\n\n### Patches\nUpgrade to [3.0.7](https://rubygems.org/gems/carrierwave/versions/3.0.7) or [2.2.6](https://rubygems.org/gems/carrierwave/versions/2.2.6).\n\n### Workarounds\nUse the following monkey patch to let CarrierWave parse the Content-type by using `Marcel::MimeType.for`.\n\n```ruby\n# For CarrierWave 3.x\nCarrierWave::SanitizedFile.class_eval do\n  def declared_content_type\n    @declared_content_type ||\n      if @file.respond_to?(:content_type) \u0026\u0026 @file.content_type\n        Marcel::MimeType.for(declared_type: @file.content_type.to_s.chomp)\n      end\n  end\nend\n```\n\n```ruby\n# For CarrierWave 2.x\nCarrierWave::SanitizedFile.class_eval do\n  def existing_content_type\n    if @file.respond_to?(:content_type) \u0026\u0026 @file.content_type\n      Marcel::MimeType.for(declared_type: @file.content_type.to_s.chomp)\n    end\n  end\nend\n```\n\n### References\n[OWASP - File Upload Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html#content-type-validation)\n\n",
  "id": "GHSA-vfmv-jfc5-pjjw",
  "modified": "2024-03-27T13:00:01Z",
  "published": "2024-03-25T19:40:36Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/carrierwaveuploader/carrierwave/security/advisories/GHSA-vfmv-jfc5-pjjw"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-29034"
    },
    {
      "type": "WEB",
      "url": "https://github.com/carrierwaveuploader/carrierwave/commit/25b1c800d45ef8e78dc445ebe3bd8a6e3f0a3477"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/carrierwaveuploader/carrierwave"
    },
    {
      "type": "WEB",
      "url": "https://github.com/rubysec/ruby-advisory-db/blob/master/gems/carrierwave/CVE-2024-29034.yml"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:N/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "CarrierWave content-Type allowlist bypass vulnerability which possibly leads to XSS remained"
}

No mitigation information available for this CWE.

CAPEC-105: HTTP Request Splitting

An adversary abuses the flexibility and discrepancies in the parsing and interpretation of HTTP Request messages by different intermediary HTTP agents (e.g., load balancer, reverse proxy, web caching proxies, application firewalls, etc.) to split a single HTTP request into multiple unauthorized and malicious HTTP requests to a back-end HTTP agent (e.g., web server).

See CanPrecede relationships for possible consequences.

CAPEC-273: HTTP Response Smuggling

An adversary manipulates and injects malicious content in the form of secret unauthorized HTTP responses, into a single HTTP response from a vulnerable or compromised back-end HTTP agent (e.g., server).

See CanPrecede relationships for possible consequences.

CAPEC-34: HTTP Response Splitting

An adversary manipulates and injects malicious content, in the form of secret unauthorized HTTP responses, into a single HTTP response from a vulnerable or compromised back-end HTTP agent (e.g., web server) or into an already spoofed HTTP response from an adversary controlled domain/site.

See CanPrecede relationships for possible consequences.