Common Weakness Enumeration

CWE-180

Allowed

Incorrect Behavior Order: Validate Before Canonicalize

Abstraction: Variant · Status: Draft

The product validates input before it is canonicalized, which prevents the product from detecting data that becomes invalid after the canonicalization step.

74 vulnerabilities reference this CWE, most recent first.

GHSA-F7VP-7XGX-4W4R

Vulnerability from github – Published: 2026-08-03 21:05 – Updated: 2026-08-03 21:05
VLAI
Summary
Guzzle: Noncanonical cookie domain keeps subdomain scope
Details

Impact

SetCookie::matchesDomain() gives every subdomain of a cookie Domain that cookie unless it recognizes the Domain as an IP literal or a numeric host, and it decides that from the domain's own text, so two spellings a transport reads as an address keep subdomain scope. On 7.15, hexadecimal and mixed-base forms such as 0x7f000001 and 0177.0.0.0x1 go unrecognized while libcurl 8.21.0 reads both as 127.0.0.1, so closing them completes the rule GHSA-g446-98w2-8p5w (CVE-2026-59883) set out to establish, which cited the WHATWG IPv4 parser and so already admitted a 0x part. A percent-escaped Domain keeps that scope on both branches for a different reason: percent-decoding sits above numeric parsing, so 192.168.0.%31 and 127.0.0.1%2e are registered names in the URI grammar rather than address literals, and no numeric rule in any base classifies them, while libcurl decodes the host before it resolves and reads them as 192.168.0.1 and 127.0.0.1. The escape must fall in the rightmost label on 8.0.0, which already catches a decimal, octal or 0x part there, but not on 7.15, where %31%32%37.0.0.0x1 also reads as 127.0.0.1; 8.0.0 is affected in the percent spelling alone.

Both directions of the defect are reproduced over a real socket. A cookie stored for Domain=0x7f000001 is placed in the Cookie header of a request to evil.0x7f000001, disclosing a session identifier or token to a host that is not that address, and a response from evil.0x7f000001 setting Domain=0x7f000001 is accepted into the jar and replayed to the address, so a server answering for the look-alike name can fix a session or set application state.

Exploitation requires the application to enable cookie support, address an origin by one of these spellings, and contact a host whose name ends in it. No public DNS delegation provides such a name, so the exposure is to private, split-horizon and container zones. Applications that do not use Guzzle's cookies, that keep a separate jar for each host or trust boundary, or that address origins only by ordinary names are not affected.

Patches

This is a summary; the patches are the authority. The issue is fixed in 7.15.2 and 8.0.1, which hold a cookie Domain containing a % byte to an exact match against the request host. 7.15.2 additionally holds to an exact match a Domain whose every dot-separated part is decimal, octal or hexadecimal, a rule wide enough that 0x100000000, a name to libcurl, loses subdomain matching too; 8.0.0 already recognizes a 0x-prefixed rightmost label. One class stays open: an IDN-capable transport reads a fullwidth-digit Domain such as 127.0.0.1 as 127.0.0.1 while Guzzle matches it by suffix, and these patches do not close that. Versions before 7.15.2 and version 8.0.0 are affected, 8.0.0 in the percent spelling alone.

Workarounds

If you cannot upgrade, do not share one CookieJar between an origin addressed by a numeric or percent-escaped spelling and any other host ending in that spelling. Use a separate jar for each host or trust boundary, or address such an origin by its canonical dotted-decimal form, writing 127.0.0.1, which released versions already hold to an exact match, rather than 0x7f000001 or 127.0.0.%31. Rejecting a request URI host that contains a percent escape, before you hand the URI to Guzzle and on every redirect hop, closes that spelling, and rejecting a non-ASCII byte closes the fullwidth one, but nothing outside the jar closes the hexadecimal one.

Do not use filter_var() with FILTER_VALIDATE_IP to decide whether a domain is an address: it rejects 0x7f000001 and 127.0.0.%31, which a transport reads as 127.0.0.1.

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-69245"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-180",
      "CWE-346",
      "CWE-384"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-08-03T21:05:26Z",
    "nvd_published_at": null,
    "severity": "MODERATE"
  },
  "details": "### Impact\n\n`SetCookie::matchesDomain()` gives every subdomain of a cookie `Domain` that cookie unless it recognizes the `Domain` as an IP literal or a numeric host, and it decides that from the domain\u0027s own text, so two spellings a transport reads as an address keep subdomain scope. On `7.15`, hexadecimal and mixed-base forms such as `0x7f000001` and `0177.0.0.0x1` go unrecognized while libcurl 8.21.0 reads both as `127.0.0.1`, so closing them completes the rule `GHSA-g446-98w2-8p5w` (`CVE-2026-59883`) set out to establish, which cited the WHATWG IPv4 parser and so already admitted a `0x` part. A percent-escaped `Domain` keeps that scope on both branches for a different reason: percent-decoding sits above numeric parsing, so `192.168.0.%31` and `127.0.0.1%2e` are registered names in the URI grammar rather than address literals, and no numeric rule in any base classifies them, while libcurl decodes the host before it resolves and reads them as `192.168.0.1` and `127.0.0.1`. The escape must fall in the rightmost label on `8.0.0`, which already catches a decimal, octal or `0x` part there, but not on `7.15`, where `%31%32%37.0.0.0x1` also reads as `127.0.0.1`; `8.0.0` is affected in the percent spelling alone.\n\nBoth directions of the defect are reproduced over a real socket. A cookie stored for `Domain=0x7f000001` is placed in the `Cookie` header of a request to `evil.0x7f000001`, disclosing a session identifier or token to a host that is not that address, and a response from `evil.0x7f000001` setting `Domain=0x7f000001` is accepted into the jar and replayed to the address, so a server answering for the look-alike name can fix a session or set application state.\n\nExploitation requires the application to enable cookie support, address an origin by one of these spellings, and contact a host whose name ends in it. No public DNS delegation provides such a name, so the exposure is to private, split-horizon and container zones. Applications that do not use Guzzle\u0027s cookies, that keep a separate jar for each host or trust boundary, or that address origins only by ordinary names are not affected.\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 hold a cookie `Domain` containing a `%` byte to an exact match against the request host. `7.15.2` additionally holds to an exact match a `Domain` whose every dot-separated part is decimal, octal or hexadecimal, a rule wide enough that `0x100000000`, a name to libcurl, loses subdomain matching too; `8.0.0` already recognizes a `0x`-prefixed rightmost label. One class stays open: an IDN-capable transport reads a fullwidth-digit `Domain` such as `127.0.0.\uff11` as `127.0.0.1` while Guzzle matches it by suffix, and these patches do not close that. Versions before `7.15.2` and version `8.0.0` are affected, `8.0.0` in the percent spelling alone.\n\n### Workarounds\n\nIf you cannot upgrade, do not share one `CookieJar` between an origin addressed by a numeric or percent-escaped spelling and any other host ending in that spelling. Use a separate jar for each host or trust boundary, or address such an origin by its canonical dotted-decimal form, writing `127.0.0.1`, which released versions already hold to an exact match, rather than `0x7f000001` or `127.0.0.%31`. Rejecting a request URI host that contains a percent escape, before you hand the URI to Guzzle and on every redirect hop, closes that spelling, and rejecting a non-ASCII byte closes the fullwidth one, but nothing outside the jar closes the hexadecimal one.\n\nDo not use `filter_var()` with `FILTER_VALIDATE_IP` to decide whether a domain is an address: it rejects `0x7f000001` and `127.0.0.%31`, which a transport reads as `127.0.0.1`.",
  "id": "GHSA-f7vp-7xgx-4w4r",
  "modified": "2026-08-03T21:05:26Z",
  "published": "2026-08-03T21:05:26Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/guzzle/guzzle/security/advisories/GHSA-f7vp-7xgx-4w4r"
    },
    {
      "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:U/C:L/I:L/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Guzzle: Noncanonical cookie domain keeps subdomain scope"
}

GHSA-FPJ5-PCGC-34G7

Vulnerability from github – Published: 2022-07-21 00:00 – Updated: 2024-10-03 18:30
VLAI
Details

A vulnerability in multiple Atlassian products allows a remote, unauthenticated attacker to cause additional Servlet Filters to be invoked when the application processes requests or responses. Atlassian has confirmed and fixed the only known security issue associated with this vulnerability: Cross-origin resource sharing (CORS) bypass. Sending a specially crafted HTTP request can invoke the Servlet Filter used to respond to CORS requests, resulting in a CORS bypass. An attacker that can trick a user into requesting a malicious URL can access the vulnerable application with the victim’s permissions. Atlassian Bamboo versions are affected before 8.0.9, from 8.1.0 before 8.1.8, and from 8.2.0 before 8.2.4. Atlassian Bitbucket versions are affected before 7.6.16, from 7.7.0 before 7.17.8, from 7.18.0 before 7.19.5, from 7.20.0 before 7.20.2, from 7.21.0 before 7.21.2, and versions 8.0.0 and 8.1.0. Atlassian Confluence versions are affected before 7.4.17, from 7.5.0 before 7.13.7, from 7.14.0 before 7.14.3, from 7.15.0 before 7.15.2, from 7.16.0 before 7.16.4, from 7.17.0 before 7.17.4, and version 7.21.0. Atlassian Crowd versions are affected before 4.3.8, from 4.4.0 before 4.4.2, and version 5.0.0. Atlassian Fisheye and Crucible versions before 4.8.10 are affected. Atlassian Jira versions are affected before 8.13.22, from 8.14.0 before 8.20.10, and from 8.21.0 before 8.22.4. Atlassian Jira Service Management versions are affected before 4.13.22, from 4.14.0 before 4.20.10, and from 4.21.0 before 4.22.4.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2022-26137"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-180",
      "CWE-346"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2022-07-20T18:15:00Z",
    "severity": "HIGH"
  },
  "details": "A vulnerability in multiple Atlassian products allows a remote, unauthenticated attacker to cause additional Servlet Filters to be invoked when the application processes requests or responses. Atlassian has confirmed and fixed the only known security issue associated with this vulnerability: Cross-origin resource sharing (CORS) bypass. Sending a specially crafted HTTP request can invoke the Servlet Filter used to respond to CORS requests, resulting in a CORS bypass. An attacker that can trick a user into requesting a malicious URL can access the vulnerable application with the victim\u2019s permissions. Atlassian Bamboo versions are affected before 8.0.9, from 8.1.0 before 8.1.8, and from 8.2.0 before 8.2.4. Atlassian Bitbucket versions are affected before 7.6.16, from 7.7.0 before 7.17.8, from 7.18.0 before 7.19.5, from 7.20.0 before 7.20.2, from 7.21.0 before 7.21.2, and versions 8.0.0 and 8.1.0. Atlassian Confluence versions are affected before 7.4.17, from 7.5.0 before 7.13.7, from 7.14.0 before 7.14.3, from 7.15.0 before 7.15.2, from 7.16.0 before 7.16.4, from 7.17.0 before 7.17.4, and version 7.21.0. Atlassian Crowd versions are affected before 4.3.8, from 4.4.0 before 4.4.2, and version 5.0.0. Atlassian Fisheye and Crucible versions before 4.8.10 are affected. Atlassian Jira versions are affected before 8.13.22, from 8.14.0 before 8.20.10, and from 8.21.0 before 8.22.4. Atlassian Jira Service Management versions are affected before 4.13.22, from 4.14.0 before 4.20.10, and from 4.21.0 before 4.22.4.",
  "id": "GHSA-fpj5-pcgc-34g7",
  "modified": "2024-10-03T18:30:34Z",
  "published": "2022-07-21T00:00:27Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-26137"
    },
    {
      "type": "WEB",
      "url": "https://jira.atlassian.com/browse/BAM-21795"
    },
    {
      "type": "WEB",
      "url": "https://jira.atlassian.com/browse/BSERV-13370"
    },
    {
      "type": "WEB",
      "url": "https://jira.atlassian.com/browse/CONFSERVER-79476"
    },
    {
      "type": "WEB",
      "url": "https://jira.atlassian.com/browse/CRUC-8541"
    },
    {
      "type": "WEB",
      "url": "https://jira.atlassian.com/browse/CWD-5815"
    },
    {
      "type": "WEB",
      "url": "https://jira.atlassian.com/browse/FE-7410"
    },
    {
      "type": "WEB",
      "url": "https://jira.atlassian.com/browse/JRASERVER-73897"
    },
    {
      "type": "WEB",
      "url": "https://jira.atlassian.com/browse/JSDSERVER-11863"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-G966-83W7-6W38

Vulnerability from github – Published: 2026-02-12 15:29 – Updated: 2026-02-12 22:07
VLAI
Summary
FrankenPHP's unicode case-folding length expansion causes incorrect split_path index (SCRIPT_NAME/PATH_INFO confusion) in FrankenPHP
Details

Summary

FrankenPHP’s CGI path splitting logic improperly handles Unicode characters during case conversion. The logic computes the split index (for finding .php) on a lowercased copy of the request path but applies that byte index to the original path.

Because strings.ToLower() in Go can increase the byte length of certain UTF-8 characters (e.g., Ⱥ expands when lowercased), the computed index may not align with the correct position in the original string. This results in an incorrect SCRIPT_NAME and SCRIPT_FILENAME, potentially causing FrankenPHP to execute a file other than the one intended by the URI.

Details

The vulnerability resides in the splitPos() function and its usage within splitCgiPath(). The logic attempts to find the script extension (e.g., .php) in a case-insensitive manner by lowercasing the path:

lowerPath := strings.ToLower(path)
idx := strings.Index(lowerPath, strings.ToLower(split))
return idx + len(split)

The issue is that the returned idx represents a byte offset within lowerPath. However, splitCgiPath() uses this index to slice the original path:

fc.docURI = path[:splitPos]
fc.pathInfo = path[splitPos:]
fc.scriptName = strings.TrimSuffix(path, fc.pathInfo)
fc.scriptFilename = sanitizedPathJoin(fc.documentRoot, fc.scriptName)

This logic relies on the assumption that len(strings.ToLower(path)) == len(path). This assumption is false for certain Unicode characters. For example, the character Ⱥ (U+023A) requires 2 bytes in UTF-8 (0xC8 0xBA), but its lowercase equivalent ⱥ (U+2C65) requires 3 bytes (0xE2 0xB1 0xA5).

If the path contains such characters before the .php extension, the index calculated on lowerPath will be larger than the corresponding visual point in the original path. When applied to the original path, the split occurs at the wrong byte offset. This can cause the server to treat a larger portion of the path as the script name, effectively allowing an attacker to manipulate SCRIPT_FILENAME.

PoC

The following Go program demonstrates the discrepancy between the byte index in the lowercased string versus the original string.

  1. Save the following as poc.go:
package main

import (
    "fmt"
    "strings"
)

func splitPos(path string, split string) int {
    lowerPath := strings.ToLower(path)
    idx := strings.Index(lowerPath, strings.ToLower(split))
    if idx < 0 {
        return -1
    }
    return idx + len(split)
}

func main() {
    // U+023A: Ⱥ (UTF-8: C8 BA). Lowercase is ⱥ (UTF-8: E2 B1 A5), longer in bytes.
    // We construct a path where the byte expansion shifts the index.
    path := "/ȺȺȺȺshell.php.txt.php"
    split := ".php"

    pos := splitPos(path, split)

    fmt.Printf("orig bytes=%d\n", len(path))
    fmt.Printf("lower bytes=%d\n", len(strings.ToLower(path)))
    fmt.Printf("splitPos=%d\n", pos)

    // Current Unsafe Behavior:
    fmt.Printf("orig[:pos] (Calculated Script)=%q\n", path[:pos])
    fmt.Printf("orig[pos:] (Calculated PathInfo)=%q\n", path[pos:])

    // Expected Safe Behavior:
    want := strings.Index(path, split) + len(split)
    fmt.Printf("expected splitPos=%d\n", want)
    fmt.Printf("expected orig[:]=%q\n", path[:want])
}
  1. Run the PoC:
go run poc.go
  1. Output:
orig bytes=26
lower bytes=30
splitPos=22
orig[:pos]="/ȺȺȺȺshell.php.txt"
orig[pos:]=".php"
expected splitPos=18
expected orig[:]="/ȺȺȺȺshell.php"

In this example, FrankenPHP would identify /ȺȺȺȺshell.php.txt as the PHP script to execute, ignoring the fact that the actual file extension in the file system might be .txt.

Impact*

This is a Security Boundary Bypass and Path Confusion vulnerability.

In setups where users can upload files (e.g., avatars, text files) that are stored within the document root or a reachable path, an attacker can upload a file containing malicious PHP code with a safe extension (e.g., payload.txt). By crafting a request with specific Unicode characters, the attacker can force FrankenPHP to calculate the SCRIPT_FILENAME as ending in payload.txt, while the request appears to contain .php to the internal router logic.

This results in the execution of non-PHP files as PHP scripts, leading to Remote Code Execution (RCE).

Patched Versions

  • This issue is fixed in FrankenPHP version 1.11.2.

Workarounds

  • Ensure that user-uploaded files are stored outside of the public document root.
  • Implement strict WAF rules to reject requests containing specific multi-byte Unicode characters in the URL path if an upgrade is not immediately possible.
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/dunglas/frankenphp"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.11.2"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-24895"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-180",
      "CWE-20"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-02-12T15:29:36Z",
    "nvd_published_at": "2026-02-12T20:16:10Z",
    "severity": "HIGH"
  },
  "details": "### Summary\n\nFrankenPHP\u2019s CGI path splitting logic improperly handles Unicode characters during case conversion. The logic computes the split index (for finding `.php`) on a lowercased copy of the request path but applies that byte index to the original path.\n\nBecause `strings.ToLower()` in Go can increase the byte length of certain UTF-8 characters (e.g., `\u023a` expands when lowercased), the computed index may not align with the correct position in the original string. This results in an incorrect `SCRIPT_NAME` and `SCRIPT_FILENAME`, potentially causing FrankenPHP to execute a file other than the one intended by the URI.\n\n### **Details**\n\nThe vulnerability resides in the `splitPos()` function and its usage within `splitCgiPath()`. The logic attempts to find the script extension (e.g., `.php`) in a case-insensitive manner by lowercasing the path:\n\n```go\nlowerPath := strings.ToLower(path)\nidx := strings.Index(lowerPath, strings.ToLower(split))\nreturn idx + len(split)\n```\n\nThe issue is that the returned `idx` represents a byte offset within `lowerPath`. However, `splitCgiPath()` uses this index to slice the **original** `path`:\n\n```go\nfc.docURI = path[:splitPos]\nfc.pathInfo = path[splitPos:]\nfc.scriptName = strings.TrimSuffix(path, fc.pathInfo)\nfc.scriptFilename = sanitizedPathJoin(fc.documentRoot, fc.scriptName)\n```\n\nThis logic relies on the assumption that `len(strings.ToLower(path)) == len(path)`. This assumption is false for certain Unicode characters. For example, the character `\u023a` (U+023A) requires 2 bytes in UTF-8 (`0xC8 0xBA`), but its lowercase equivalent `\u2c65` (U+2C65) requires 3 bytes (`0xE2 0xB1 0xA5`).\n\nIf the path contains such characters before the `.php` extension, the index calculated on `lowerPath` will be larger than the corresponding visual point in the original `path`. When applied to the original path, the split occurs at the wrong byte offset. This can cause the server to treat a larger portion of the path as the script name, effectively allowing an attacker to manipulate `SCRIPT_FILENAME`.\n\n### **PoC**\n\nThe following Go program demonstrates the discrepancy between the byte index in the lowercased string versus the original string.\n\n1. Save the following as `poc.go`:\n\n```go\npackage main\n\nimport (\n    \"fmt\"\n    \"strings\"\n)\n\nfunc splitPos(path string, split string) int {\n    lowerPath := strings.ToLower(path)\n    idx := strings.Index(lowerPath, strings.ToLower(split))\n    if idx \u003c 0 {\n        return -1\n    }\n    return idx + len(split)\n}\n\nfunc main() {\n    // U+023A: \u023a (UTF-8: C8 BA). Lowercase is \u2c65 (UTF-8: E2 B1 A5), longer in bytes.\n    // We construct a path where the byte expansion shifts the index.\n    path := \"/\u023a\u023a\u023a\u023ashell.php.txt.php\"\n    split := \".php\"\n\n    pos := splitPos(path, split)\n\n    fmt.Printf(\"orig bytes=%d\\n\", len(path))\n    fmt.Printf(\"lower bytes=%d\\n\", len(strings.ToLower(path)))\n    fmt.Printf(\"splitPos=%d\\n\", pos)\n\n    // Current Unsafe Behavior:\n    fmt.Printf(\"orig[:pos] (Calculated Script)=%q\\n\", path[:pos])\n    fmt.Printf(\"orig[pos:] (Calculated PathInfo)=%q\\n\", path[pos:])\n\n    // Expected Safe Behavior:\n    want := strings.Index(path, split) + len(split)\n    fmt.Printf(\"expected splitPos=%d\\n\", want)\n    fmt.Printf(\"expected orig[:]=%q\\n\", path[:want])\n}\n```\n\n2. Run the PoC:\n\n```console\ngo run poc.go\n```\n\n3. **Output:**\n\n```text\norig bytes=26\nlower bytes=30\nsplitPos=22\norig[:pos]=\"/\u023a\u023a\u023a\u023ashell.php.txt\"\norig[pos:]=\".php\"\nexpected splitPos=18\nexpected orig[:]=\"/\u023a\u023a\u023a\u023ashell.php\"\n```\n\nIn this example, FrankenPHP would identify `/\u023a\u023a\u023a\u023ashell.php.txt` as the PHP script to execute, ignoring the fact that the actual file extension in the file system might be `.txt`.\n\n### Impact*\n\nThis is a **Security Boundary Bypass** and **Path Confusion** vulnerability.\n\nIn setups where users can upload files (e.g., avatars, text files) that are stored within the document root or a reachable path, an attacker can upload a file containing malicious PHP code with a safe extension (e.g., `payload.txt`). By crafting a request with specific Unicode characters, the attacker can force FrankenPHP to calculate the `SCRIPT_FILENAME` as ending in `payload.txt`, while the request appears to contain `.php` to the internal router logic.\n\nThis results in the execution of non-PHP files as PHP scripts, leading to **Remote Code Execution (RCE)**.\n\n### **Patched Versions**\n\n* This issue is fixed in FrankenPHP version **1.11.2**.\n\n### **Workarounds**\n\n* Ensure that user-uploaded files are stored outside of the public document root.\n* Implement strict WAF rules to reject requests containing specific multi-byte Unicode characters in the URL path if an upgrade is not immediately possible.",
  "id": "GHSA-g966-83w7-6w38",
  "modified": "2026-02-12T22:07:57Z",
  "published": "2026-02-12T15:29:36Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/php/frankenphp/security/advisories/GHSA-g966-83w7-6w38"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-24895"
    },
    {
      "type": "WEB",
      "url": "https://github.com/php/frankenphp/commit/04fdc0c1e8fde94e2c1ad86217e962c88d27c53e"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/php/frankenphp"
    },
    {
      "type": "WEB",
      "url": "https://github.com/php/frankenphp/releases/tag/v1.11.2"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:P/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
      "type": "CVSS_V4"
    }
  ],
  "summary": "FrankenPHP\u0027s unicode case-folding length expansion causes incorrect split_path index (SCRIPT_NAME/PATH_INFO confusion) in FrankenPHP"
}

GHSA-HXM8-2XGR-2P9M

Vulnerability from github – Published: 2026-09-29 23:17 – Updated: 2026-09-29 23:17
VLAI
Summary
PyJWT: Non-canonical signature segments enable raw-token revocation bypass
Details

Summary

PyJWT 2.13.0 accepts compact JWS signature segments containing characters that are not in the Base64URL alphabet. Appending !!!! to a valid signature does not change the decoded signature bytes or authenticated claims, but it changes the serialized token and its SHA-256 hash. An application that indexes logout or revocation state by the raw token therefore rejects the logged-out token and accepts its no-key alternate serialization.

This report separates two issues: permissive compact-JWS decoding is the library behavior, while using raw serialized JWT text as a security identity is a dangerous application composition. A jti-indexed control blocks both representations.

Affected Version

Confirmed with PyJWT 2.13.0 on CPython 3.13. The mutation changes only the signature segment and requires no signing key.

End-to-End Reproduction

.venv-research/bin/python 06-practical-testing/revocation-bypass-lab.py

The loopback-only lab performs:

  1. Issue a valid HS256 admin token.
  2. Access /protected successfully.
  3. Log out the canonical token and store SHA256(raw_token).
  4. Confirm canonical replay returns HTTP 401.
  5. Append !!!! to only the signature segment.
  6. Confirm the mutated token has the same verified claims and signature bytes, a different raw hash, and receives HTTP 200.
  7. Repeat with jti-indexed revocation and confirm both forms return HTTP 401.

Observed statuses for raw-token revocation were 200 -> logout -> 401 for the canonical token and 200 for the alternate serialization. The jti control returned 401 for both replays after logout.

Security Boundaries and Severity

This is not signature forgery: the attacker starts with a valid token and cannot alter its claims. Impact requires a consumer to bind revocation, replay state, rate limits, or cache identity to the raw compact string. Under that composition, an authenticated user can bypass logout or token-specific revocation without the signing key. Medium is suggested for triage because the security impact is real but application-dependent.

Recommended Fix

  • Reject signature segments containing characters outside [A-Za-z0-9_-].
  • Reject padding and other non-canonical Base64URL encodings for compact JWS.
  • Add regression tests proving malformed signature encodings fail before or during verification.
  • Document that applications must use a semantic identifier such as jti, not the raw serialized token, for revocation and replay state.

Maintainer update — 2026-09-09

We reproduced the reported behavior on the verified master commit 8915570: appending !!!! to a valid compact-JWS signature segment is accepted, produces the same decoded signature bytes and claims, and changes the serialized token hash. Existing JWS verification controls pass. The behavior is present in the tested release range represented by tags 2.4.0, 2.8.0, 2.10.1, 2.12.1, and 2.13.0.

The security impact is conditional on an application using the raw serialized token as the identity for logout, revocation, replay, rate-limit, or cache state. Under that composition, an attacker who already holds a valid token can use an alternate serialization after the canonical string is revoked. This is not signature forgery or claim alteration; applications should use a semantic identifier such as jti for token identity.

The report is ready to be accepted as a draft for continued remediation. A narrow fix assessment recommends rejecting non-canonical Base64URL characters and padding in compact-JWS segments. No fix commit or release is claimed yet.

Maintainer update — 2026-09-09

The fix has been rebased onto the current master as e6f48401001609a8f99e71fcaf355fb895d508a8 and is ready to be pushed. Compact-JWS header, payload, and signature segments are now required to use the unpadded Base64URL alphabet and canonical re-encoding; a signature segment containing non-canonical characters such as !!!! is rejected before verification. Valid detached b64=false handling remains supported.

Verification on the rebased fix commit passed 372 tests with 4 intentional cryptography-environment skips; Ruff formatting/lint and git diff --check passed. The compressed-payload regression fixture was updated to valid canonical compact-JWS encoding. No release containing the fix has been published yet, so the patched version remains unset pending release planning.

The advisory remains medium severity and unpublished.

Classification update — 2026-09-10

We completed the advisory classification review. The proposed CVSS 3.1 vector is CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N and the proposed CWE classification is CWE-180. The issue permits alternate non-canonical serializations of an already valid signed token to bypass applications that identify tokens by their raw serialization; it does not forge signatures or alter claims. CWE-180 captures validation/canonicalization ordering.

These metadata changes do not alter the affected range, fix status, or lifecycle state.

Maintainer update — 2026-09-11

The verified fix for this advisory is included in PyJWT 2.14.0, released on 2026-09-11 and available on PyPI. PyJWT 2.14.0 is the first release containing the fix. This advisory is now published with 2.14.0 recorded as the patched version.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 2.13.0"
      },
      "package": {
        "ecosystem": "PyPI",
        "name": "PyJWT"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "2.14.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-102269"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-180"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-09-29T23:17:55Z",
    "nvd_published_at": "2026-09-28T21:17:14Z",
    "severity": "MODERATE"
  },
  "details": "## Summary\n\nPyJWT 2.13.0 accepts compact JWS signature segments containing characters that\nare not in the Base64URL alphabet. Appending `!!!!` to a valid signature does\nnot change the decoded signature bytes or authenticated claims, but it changes\nthe serialized token and its SHA-256 hash. An application that indexes logout\nor revocation state by the raw token therefore rejects the logged-out token and\naccepts its no-key alternate serialization.\n\nThis report separates two issues: permissive compact-JWS decoding is the\nlibrary behavior, while using raw serialized JWT text as a security identity is\na dangerous application composition. A `jti`-indexed control blocks both\nrepresentations.\n\n## Affected Version\n\nConfirmed with PyJWT 2.13.0 on CPython 3.13. The mutation changes only the\nsignature segment and requires no signing key.\n\n## End-to-End Reproduction\n\n```bash\n.venv-research/bin/python 06-practical-testing/revocation-bypass-lab.py\n```\n\nThe loopback-only lab performs:\n\n1. Issue a valid HS256 admin token.\n2. Access `/protected` successfully.\n3. Log out the canonical token and store `SHA256(raw_token)`.\n4. Confirm canonical replay returns HTTP 401.\n5. Append `!!!!` to only the signature segment.\n6. Confirm the mutated token has the same verified claims and signature bytes,\n   a different raw hash, and receives HTTP 200.\n7. Repeat with `jti`-indexed revocation and confirm both forms return HTTP 401.\n\nObserved statuses for raw-token revocation were `200 -\u003e logout -\u003e 401` for the\ncanonical token and `200` for the alternate serialization. The `jti` control\nreturned `401` for both replays after logout.\n\n## Security Boundaries and Severity\n\nThis is not signature forgery: the attacker starts with a valid token and\ncannot alter its claims. Impact requires a consumer to bind revocation, replay\nstate, rate limits, or cache identity to the raw compact string. Under that\ncomposition, an authenticated user can bypass logout or token-specific\nrevocation without the signing key. Medium is suggested for triage because the\nsecurity impact is real but application-dependent.\n\n## Recommended Fix\n\n- Reject signature segments containing characters outside `[A-Za-z0-9_-]`.\n- Reject padding and other non-canonical Base64URL encodings for compact JWS.\n- Add regression tests proving malformed signature encodings fail before or\n  during verification.\n- Document that applications must use a semantic identifier such as `jti`, not\n  the raw serialized token, for revocation and replay state.\n\n## Maintainer update \u2014 2026-09-09\n\nWe reproduced the reported behavior on the verified `master` commit `8915570`: appending `!!!!` to a valid compact-JWS signature segment is accepted, produces the same decoded signature bytes and claims, and changes the serialized token hash. Existing JWS verification controls pass. The behavior is present in the tested release range represented by tags `2.4.0`, `2.8.0`, `2.10.1`, `2.12.1`, and `2.13.0`.\n\nThe security impact is conditional on an application using the raw serialized token as the identity for logout, revocation, replay, rate-limit, or cache state. Under that composition, an attacker who already holds a valid token can use an alternate serialization after the canonical string is revoked. This is not signature forgery or claim alteration; applications should use a semantic identifier such as `jti` for token identity.\n\nThe report is ready to be accepted as a draft for continued remediation. A narrow fix assessment recommends rejecting non-canonical Base64URL characters and padding in compact-JWS segments. No fix commit or release is claimed yet.\n\n### Maintainer update \u2014 2026-09-09\n\nThe fix has been rebased onto the current `master` as `e6f48401001609a8f99e71fcaf355fb895d508a8` and is ready to be pushed. Compact-JWS header, payload, and signature segments are now required to use the unpadded Base64URL alphabet and canonical re-encoding; a signature segment containing non-canonical characters such as `!!!!` is rejected before verification. Valid detached `b64=false` handling remains supported.\n\nVerification on the rebased fix commit passed 372 tests with 4 intentional cryptography-environment skips; Ruff formatting/lint and `git diff --check` passed. The compressed-payload regression fixture was updated to valid canonical compact-JWS encoding. No release containing the fix has been published yet, so the patched version remains unset pending release planning.\n\nThe advisory remains medium severity and unpublished.\n\n## Classification update \u2014 2026-09-10\n\nWe completed the advisory classification review. The proposed CVSS 3.1 vector is `CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N` and the proposed CWE classification is CWE-180. The issue permits alternate non-canonical serializations of an already valid signed token to bypass applications that identify tokens by their raw serialization; it does not forge signatures or alter claims. CWE-180 captures validation/canonicalization ordering.\n\nThese metadata changes do not alter the affected range, fix status, or lifecycle state.\n\n## Maintainer update \u2014 2026-09-11\n\nThe verified fix for this advisory is included in PyJWT 2.14.0, released on 2026-09-11 and available on PyPI. PyJWT 2.14.0 is the first release containing the fix. This advisory is now published with 2.14.0 recorded as the patched version.",
  "id": "GHSA-hxm8-2xgr-2p9m",
  "modified": "2026-09-29T23:17:55Z",
  "published": "2026-09-29T23:17:55Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/jpadilla/pyjwt/security/advisories/GHSA-hxm8-2xgr-2p9m"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-102269"
    },
    {
      "type": "WEB",
      "url": "https://github.com/jpadilla/pyjwt/commit/e6f48401001609a8f99e71fcaf355fb895d508a8"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/jpadilla/pyjwt"
    },
    {
      "type": "WEB",
      "url": "https://github.com/jpadilla/pyjwt/releases/tag/2.14.0"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "PyJWT: Non-canonical signature segments enable raw-token revocation bypass"
}

GHSA-J26J-R3XM-Q4WF

Vulnerability from github – Published: 2026-09-26 15:31 – Updated: 2026-09-26 15:31
VLAI
Details

stoatchat before 0.15.5 fails to revalidate usernames after Unicode sanitization, allowing attackers to create usernames with forbidden characters by submitting Unicode letters that transform into rejected characters. Attackers can bypass character allowlists and length limits to create reserved-name lookalikes, embed special characters, and exceed the 32-character storage limit.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-100674"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-180"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-09-26T14:16:51Z",
    "severity": "MODERATE"
  },
  "details": "stoatchat before 0.15.5 fails to revalidate usernames after Unicode sanitization, allowing attackers to create usernames with forbidden characters by submitting Unicode letters that transform into rejected characters. Attackers can bypass character allowlists and length limits to create reserved-name lookalikes, embed special characters, and exceed the 32-character storage limit.",
  "id": "GHSA-j26j-r3xm-q4wf",
  "modified": "2026-09-26T15:31:20Z",
  "published": "2026-09-26T15:31:20Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/stoatchat/stoatchat/security/advisories/GHSA-qcwh-c934-wrv5"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-100674"
    },
    {
      "type": "WEB",
      "url": "https://www.vulncheck.com/advisories/stoatchat-before-0.15.5-username-validation-bypass-via-unicode-sanitization"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
      "type": "CVSS_V4"
    }
  ]
}

GHSA-M68W-Q97C-3W3J

Vulnerability from github – Published: 2026-09-25 18:31 – Updated: 2026-09-25 18:31
VLAI
Details

Input Leap (aka input-leap) through 3.0.3, when the non-default --enable-drag-drop option is used on Windows or macOS, mishandles the / versus \ distinction and allows directory traversal, with resultant code execution if a file is written to a startup directory. This occurs via a DDRG message.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-100230"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-180"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-09-25T16:17:24Z",
    "severity": "MODERATE"
  },
  "details": "Input Leap (aka input-leap) through 3.0.3, when the non-default --enable-drag-drop option is used on Windows or macOS, mishandles the / versus \\ distinction and allows directory traversal, with resultant code execution if a file is written to a startup directory. This occurs via a DDRG message.",
  "id": "GHSA-m68w-q97c-3w3j",
  "modified": "2026-09-25T18:31:22Z",
  "published": "2026-09-25T18:31:22Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-42072"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-100230"
    },
    {
      "type": "WEB",
      "url": "https://github.com/deskflow/deskflow/security/advisories"
    },
    {
      "type": "WEB",
      "url": "https://github.com/input-leap/input-leap/blob/master/src/lib/inputleap/DropHelper.cpp"
    },
    {
      "type": "WEB",
      "url": "https://github.com/input-leap/input-leap/blob/v3.0.3/src/lib/inputleap/DragInformation.cpp"
    },
    {
      "type": "WEB",
      "url": "https://github.com/input-leap/input-leap/releases"
    },
    {
      "type": "WEB",
      "url": "https://raw.githubusercontent.com/debauchee/barrier/master/src/lib/barrier/DragInformation.cpp"
    },
    {
      "type": "WEB",
      "url": "https://raw.githubusercontent.com/input-leap/input-leap/master/src/lib/inputleap/ArgParser.cpp"
    },
    {
      "type": "WEB",
      "url": "https://raw.githubusercontent.com/input-leap/input-leap/master/src/lib/net/SecureSocket.cpp"
    },
    {
      "type": "WEB",
      "url": "https://raw.githubusercontent.com/input-leap/input-leap/v3.0.3/src/lib/server/Server.cpp"
    },
    {
      "type": "WEB",
      "url": "https://www.openwall.com/lists/oss-security/2026/09/25/4"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:H/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-M9GQ-CMCJ-P62X

Vulnerability from github – Published: 2026-03-27 21:31 – Updated: 2026-03-27 21:31
VLAI
Details

Varnish Cache before 8.0.1 and Varnish Enterprise before 6.0.16r12, in certain unchecked req.url scenarios, mishandle URLs with a path of / for HTTP/1.1, potentially leading to cache poisoning or authentication bypass.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-34475"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-180"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-03-27T20:16:36Z",
    "severity": "MODERATE"
  },
  "details": "Varnish Cache before 8.0.1 and Varnish Enterprise before 6.0.16r12, in certain unchecked req.url scenarios, mishandle URLs with a path of / for HTTP/1.1, potentially leading to cache poisoning or authentication bypass.",
  "id": "GHSA-m9gq-cmcj-p62x",
  "modified": "2026-03-27T21:31:37Z",
  "published": "2026-03-27T21:31:37Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-34475"
    },
    {
      "type": "WEB",
      "url": "https://vinyl-cache.org/security/VSV00018.html"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:L/I:L/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-Q4QF-9J86-F5MH

Vulnerability from github – Published: 2026-04-02 18:44 – Updated: 2026-05-13 15:20
VLAI
Summary
Rack:: Static header_rules bypass via URL-encoded paths
Details

Summary

Rack::Static#applicable_rules evaluates several header_rules types against the raw URL-encoded PATH_INFO, while the underlying file-serving path is decoded before the file is served. As a result, a request for a URL-encoded variant of a static path can serve the same file without the headers that header_rules were intended to apply.

In deployments that rely on Rack::Static to attach security-relevant response headers to static content, this can allow an attacker to bypass those headers by requesting an encoded form of the path.

Details

Rack::Static#applicable_rules matches rule types such as :fonts, Array, and Regexp directly against the incoming PATH_INFO. For example:

when :fonts
  /\.(?:ttf|otf|eot|woff2|woff|svg)\z/.match?(path)
when Array
  /\.(#{rule.join('|')})\z/.match?(path)
when Regexp
  rule.match?(path)

These checks operate on the raw request path. If the request contains encoded characters such as %2E in place of ., the rule may fail to match even though the file path is later decoded and served successfully by the static file server.

For example, both of the following requests may resolve to the same file on disk:

/fonts/test.woff
/fonts/test%2Ewoff

but only the unencoded form may receive the headers configured through header_rules.

This creates a canonicalization mismatch between the path used for header policy decisions and the path ultimately used for file serving.

Impact

Applications that rely on Rack::Static header_rules to apply security-relevant headers to static files may be affected.

In affected deployments, an attacker can request an encoded variant of a static file path and receive the same file without the intended headers. Depending on how header_rules are used, this may bypass protections such as clickjacking defenses, content restrictions, or other response policies applied to static content.

The practical impact depends on the configured rules and the types of files being served. If header_rules are only used for non-security purposes such as caching, the issue may have limited security significance.

Mitigation

  • Update to a patched version of Rack that applies header_rules to a decoded path consistently with static file resolution.
  • Do not rely solely on Rack::Static header_rules for security-critical headers where encoded path variants may reach the application.
  • Prefer setting security headers at the reverse proxy or web server layer so they apply consistently to both encoded and unencoded path forms.
  • Normalize or reject encoded path variants for static content at the edge, where feasible.
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "RubyGems",
        "name": "rack"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "2.2.23"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "RubyGems",
        "name": "rack"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "3.0.0.beta1"
            },
            {
              "fixed": "3.1.21"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "RubyGems",
        "name": "rack"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "3.2.0"
            },
            {
              "fixed": "3.2.6"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-34786"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-180"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-04-02T18:44:49Z",
    "nvd_published_at": "2026-04-02T17:16:25Z",
    "severity": "MODERATE"
  },
  "details": "## Summary\n\n`Rack::Static#applicable_rules` evaluates several `header_rules` types against the raw URL-encoded `PATH_INFO`, while the underlying file-serving path is decoded before the file is served. As a result, a request for a URL-encoded variant of a static path can serve the same file without the headers that `header_rules` were intended to apply.\n\nIn deployments that rely on `Rack::Static` to attach security-relevant response headers to static content, this can allow an attacker to bypass those headers by requesting an encoded form of the path.\n\n## Details\n\n`Rack::Static#applicable_rules` matches rule types such as `:fonts`, `Array`, and `Regexp` directly against the incoming `PATH_INFO`. For example:\n\n```ruby\nwhen :fonts\n  /\\.(?:ttf|otf|eot|woff2|woff|svg)\\z/.match?(path)\nwhen Array\n  /\\.(#{rule.join(\u0027|\u0027)})\\z/.match?(path)\nwhen Regexp\n  rule.match?(path)\n```\n\nThese checks operate on the raw request path. If the request contains encoded characters such as `%2E` in place of `.`, the rule may fail to match even though the file path is later decoded and served successfully by the static file server.\n\nFor example, both of the following requests may resolve to the same file on disk:\n\n```text\n/fonts/test.woff\n/fonts/test%2Ewoff\n```\n\nbut only the unencoded form may receive the headers configured through `header_rules`.\n\nThis creates a canonicalization mismatch between the path used for header policy decisions and the path ultimately used for file serving.\n\n## Impact\n\nApplications that rely on `Rack::Static` `header_rules` to apply security-relevant headers to static files may be affected.\n\nIn affected deployments, an attacker can request an encoded variant of a static file path and receive the same file without the intended headers. Depending on how `header_rules` are used, this may bypass protections such as clickjacking defenses, content restrictions, or other response policies applied to static content.\n\nThe practical impact depends on the configured rules and the types of files being served. If `header_rules` are only used for non-security purposes such as caching, the issue may have limited security significance.\n\n## Mitigation\n\n* Update to a patched version of Rack that applies `header_rules` to a decoded path consistently with static file resolution.\n* Do not rely solely on `Rack::Static` `header_rules` for security-critical headers where encoded path variants may reach the application.\n* Prefer setting security headers at the reverse proxy or web server layer so they apply consistently to both encoded and unencoded path forms.\n* Normalize or reject encoded path variants for static content at the edge, where feasible.",
  "id": "GHSA-q4qf-9j86-f5mh",
  "modified": "2026-05-13T15:20:50Z",
  "published": "2026-04-02T18:44:49Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/rack/rack/security/advisories/GHSA-q4qf-9j86-f5mh"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-34786"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/rack/rack"
    },
    {
      "type": "WEB",
      "url": "https://github.com/rubysec/ruby-advisory-db/blob/master/gems/rack/CVE-2026-34786.yml"
    }
  ],
  "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"
    }
  ],
  "summary": "Rack:: Static header_rules bypass via URL-encoded paths"
}

GHSA-QCJM-VMRX-V935

Vulnerability from github – Published: 2026-08-29 15:30 – Updated: 2026-08-29 15:30
VLAI
Details

The cohttp package before 6.3.0 for OCaml allows directory traversal.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-82481"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-180"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-08-29T15:17:55Z",
    "severity": "HIGH"
  },
  "details": "The cohttp package before 6.3.0 for OCaml allows directory traversal.",
  "id": "GHSA-qcjm-vmrx-v935",
  "modified": "2026-08-29T15:30:21Z",
  "published": "2026-08-29T15:30:21Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-82481"
    },
    {
      "type": "WEB",
      "url": "https://github.com/mirage/ocaml-cohttp/pull/1145"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:Y/R:A/V:D/RE:M/U:X",
      "type": "CVSS_V4"
    }
  ]
}

GHSA-QWGM-HFPP-4PF6

Vulnerability from github – Published: 2026-09-25 06:30 – Updated: 2026-09-25 06:30
VLAI
Details

django-allauth before 65.19.4 does not have the expected limits on failed login attempts because, in some common configurations, an attacker can leverage the handling of diacritics (e.g., accents) for a higher effective limit.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-97764"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-180"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-09-25T05:17:07Z",
    "severity": "LOW"
  },
  "details": "django-allauth before 65.19.4 does not have the expected limits on failed login attempts because, in some common configurations, an attacker can leverage the handling of diacritics (e.g., accents) for a higher effective limit.",
  "id": "GHSA-qwgm-hfpp-4pf6",
  "modified": "2026-09-25T06:30:32Z",
  "published": "2026-09-25T06:30:32Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-97764"
    },
    {
      "type": "WEB",
      "url": "https://codeberg.org/allauth/django-allauth/commit/4379e7931fe7572aacc4f3b4b5f2298d5f3ecc96"
    },
    {
      "type": "WEB",
      "url": "https://codeberg.org/allauth/django-allauth/commit/4e252aa2be7cef5d72d78049d6fb07cb27a89c83"
    },
    {
      "type": "WEB",
      "url": "https://codeberg.org/allauth/django-allauth/commit/ae472772c8f93bcb972205c9d7159051cf6f413a"
    },
    {
      "type": "WEB",
      "url": "https://docs.allauth.org/en/latest/release-notes/recent.html"
    },
    {
      "type": "WEB",
      "url": "https://pypi.org/project/django-allauth"
    }
  ],
  "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"
    }
  ]
}

Mitigation MIT-20
Implementation

Strategy: Input Validation

Inputs should be decoded and canonicalized to the application's current internal representation before being validated (CWE-180). Make sure that the application does not decode the same input twice (CWE-174). Such errors could be used to bypass allowlist validation schemes by introducing dangerous inputs after they have been checked.

CAPEC-267: Leverage Alternate Encoding

An adversary leverages the possibility to encode potentially harmful input or content used by applications such that the applications are ineffective at validating this encoding standard.

CAPEC-3: Using Leading 'Ghost' Character Sequences to Bypass Input Filters

Some APIs will strip certain leading characters from a string of parameters. An adversary can intentionally introduce leading "ghost" characters (extra characters that don't affect the validity of the request at the API layer) that enable the input to pass the filters and therefore process the adversary's input. This occurs when the targeted API will accept input data in several syntactic forms and interpret it in the equivalent semantic way, while the filter does not take into account the full spectrum of the syntactic forms acceptable to the targeted API.

CAPEC-71: Using Unicode Encoding to Bypass Validation Logic

An attacker may provide a Unicode string to a system component that is not Unicode aware and use that to circumvent the filter or cause the classifying mechanism to fail to properly understanding the request. That may allow the attacker to slip malicious data past the content filter and/or possibly cause the application to route the request incorrectly.

CAPEC-78: Using Escaped Slashes in Alternate Encoding

This attack targets the use of the backslash in alternate encoding. An adversary can provide a backslash as a leading character and causes a parser to believe that the next character is special. This is called an escape. By using that trick, the adversary tries to exploit alternate ways to encode the same character which leads to filter problems and opens avenues to attack.

CAPEC-79: Using Slashes in Alternate Encoding

This attack targets the encoding of the Slash characters. An adversary would try to exploit common filtering problems related to the use of the slashes characters to gain access to resources on the target host. Directory-driven systems, such as file systems and databases, typically use the slash character to indicate traversal between directories or other container components. For murky historical reasons, PCs (and, as a result, Microsoft OSs) choose to use a backslash, whereas the UNIX world typically makes use of the forward slash. The schizophrenic result is that many MS-based systems are required to understand both forms of the slash. This gives the adversary many opportunities to discover and abuse a number of common filtering problems. The goal of this pattern is to discover server software that only applies filters to one version, but not the other.

CAPEC-80: Using UTF-8 Encoding to Bypass Validation Logic

This attack is a specific variation on leveraging alternate encodings to bypass validation logic. This attack leverages the possibility to encode potentially harmful input in UTF-8 and submit it to applications not expecting or effective at validating this encoding standard making input filtering difficult. UTF-8 (8-bit UCS/Unicode Transformation Format) is a variable-length character encoding for Unicode. Legal UTF-8 characters are one to four bytes long. However, early version of the UTF-8 specification got some entries wrong (in some cases it permitted overlong characters). UTF-8 encoders are supposed to use the "shortest possible" encoding, but naive decoders may accept encodings that are longer than necessary. According to the RFC 3629, a particularly subtle form of this attack can be carried out against a parser which performs security-critical validity checks against the UTF-8 encoded form of its input, but interprets certain illegal octet sequences as characters.