GHSA-2FVJ-HGJ9-J2GR

Vulnerability from github – Published: 2026-07-22 22:55 – Updated: 2026-07-22 22:55
VLAI
Summary
Eclipse Jetty Digest Authentication: ISO-8859-1 lossy encoding allows authentication bypass via character substitution
Details

Summary

The DigestAuthentication.apply() method in Jetty's HTTP client uses getBytes(StandardCharsets.ISO_8859_1) at three locations (lines 171, 179, 196) to compute Digest auth response hashes. ISO-8859-1 silently replaces any character above U+00FF (Chinese, Japanese, Cyrillic, Arabic, Emoji, etc.) with 0x3F (?), causing all such characters to produce identical hash contributions. An attacker who knows a victim's username can bypass Digest authentication by replacing all non-Latin-1 characters in the password with ? characters, since the collision password produces the same MD5-based Digest response hash as the original password.

Details

Root Cause

In jetty-core/jetty-client/src/main/java/org/eclipse/jetty/client/DigestAuthentication.java, the apply() method computes the three Digest auth hashes (H(A1), H(A2), and the final response) using ISO-8859-1 character encoding:

// Line 171 — H(A1)
String hashA1 = toHexString(digester.digest(a1.getBytes(StandardCharsets.ISO_8859_1)));

// Line 179 — H(A2)
String hashA2 = toHexString(digester.digest(a2.getBytes(StandardCharsets.ISO_8859_1)));

// Line 196 — Final response hash
final String hashA3 = toHexString(digester.digest(a3.getBytes(StandardCharsets.ISO_8859_1)));

ISO-8859-1 (Latin-1) can only encode characters in the range U+0000–U+00FF. Any character outside this range — including all CJK, Cyrillic, Arabic, Greek, Hangul, and emoji characters — is silently replaced with the byte 0x3F (?). String.getBytes(ISO_8859_1) in Java performs this replacement without any warning or exception.

PoC

Password: "我爱Java!密码123★" (7 non-Latin-1 characters)

UTF-8 encoding:    45 bytes → MD5 H(A1) = 9a4e61484f228633d5d0f95d1bbb0a99
ISO-8859-1:        31 bytes → MD5 H(A1) = d60ddc903d71913bcc3ab4a94f7fc239
Collision "??...": 31 bytes → MD5 H(A1) = d60ddc903d71913bcc3ab4a94f7fc239 ← IDENTICAL

Multi-language confirmation — all four language passwords below produce the same hash:

Chinese (密码123)  → H(A1) = db87f31e8d96cd15f9acec7eabdc4560
Korean  (비번123)  → H(A1) = db87f31e8d96cd15f9acec7eabdc4560
Cyrillic(аб123)    → H(A1) = db87f31e8d96cd15f9acec7eabdc4560
Greek   (αβ123)    → H(A1) = db87f31e8d96cd15f9acec7eabdc4560
Attacker(??123)    → H(A1) = db87f31e8d96cd15f9acec7eabdc4560 ← all collide!

Impact

Scenario 1: Authentication Bypass (Collision Attack)

If a service using Jetty for Digest authentication has a user with a non-Latin-1 password (e.g., Chinese, Japanese, Russian), an attacker can authenticate as that user using a collision password where all non-Latin-1 characters are replaced with ?:

  • Original password: 我爱Java!密码123★
  • Collision password: ??Java!??123?
  • Both produce identical MD5 hashes under ISO-8859-1 → Authentication succeeds

This affects any password containing characters > U+00FF, which covers: - Chinese (CJK): U+4E00–U+9FFF - Japanese (Hiragana/Katakana/Kanji): U+3040–U+30FF, U+4E00+ - Korean (Hangul): U+AC00–U+D7AF - Cyrillic: U+0400–U+04FF (Russian, Ukrainian, Bulgarian, etc.) - Arabic: U+0600–U+06FF - Greek: U+0370–U+03FF - Latin Extended: U+0100–U+024F (accented European characters like ĉ, ğ, ñ when > U+00FF) - Emoji / Symbols > U+00FF

Scenario 2: Denial of Service for Non-Latin-1 Users

Most modern web applications store password hashes computed using UTF-8. When Jetty's Digest client computes a hash with ISO-8859-1, the bytes differ from what the server stored/expects. This means any user with non-ASCII (Latin-1+) characters in their password can never successfully authenticate via Digest auth — even the legitimate user. This is not just a security issue but a functional correctness bug that silently breaks authentication for most non-European-language users.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 9.4.58.v20250814"
      },
      "package": {
        "ecosystem": "Maven",
        "name": "org.eclipse.jetty:jetty-security"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "9.4.0.v20161208"
            },
            {
              "fixed": "9.4.63"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 10.0.26"
      },
      "package": {
        "ecosystem": "Maven",
        "name": "org.eclipse.jetty:jetty-security"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "10.0.0"
            },
            {
              "fixed": "10.0.31"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 11.0.26"
      },
      "package": {
        "ecosystem": "Maven",
        "name": "org.eclipse.jetty:jetty-security"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "11.0.0"
            },
            {
              "fixed": "11.0.31"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 12.0.35"
      },
      "package": {
        "ecosystem": "Maven",
        "name": "org.eclipse.jetty:jetty-security"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "12.0.0"
            },
            {
              "fixed": "12.0.36"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 12.0.35"
      },
      "package": {
        "ecosystem": "Maven",
        "name": "org.eclipse.jetty.ee8:jetty-ee8-security"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "12.0.0"
            },
            {
              "fixed": "12.0.36"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 12.0.35"
      },
      "package": {
        "ecosystem": "Maven",
        "name": "org.eclipse.jetty.ee9:jetty-ee9-security"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "12.0.0"
            },
            {
              "fixed": "12.0.36"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 12.1.9"
      },
      "package": {
        "ecosystem": "Maven",
        "name": "org.eclipse.jetty:jetty-security"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "12.1.0"
            },
            {
              "fixed": "12.1.10"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 12.1.9"
      },
      "package": {
        "ecosystem": "Maven",
        "name": "org.eclipse.jetty.ee8:jetty-ee8-security"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "12.1.0"
            },
            {
              "fixed": "12.1.10"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 12.1.9"
      },
      "package": {
        "ecosystem": "Maven",
        "name": "org.eclipse.jetty.ee9:jetty-ee9-security"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "12.1.0"
            },
            {
              "fixed": "12.1.10"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-10050"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-173",
      "CWE-303"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-07-22T22:55:18Z",
    "nvd_published_at": null,
    "severity": "HIGH"
  },
  "details": "### Summary\nThe `DigestAuthentication.apply()` method in Jetty\u0027s HTTP client uses `getBytes(StandardCharsets.ISO_8859_1)` at three locations (lines 171, 179, 196) to compute Digest auth response hashes. ISO-8859-1 silently replaces any character above U+00FF (Chinese, Japanese, Cyrillic, Arabic, Emoji, etc.) with 0x3F (`?`), causing all such characters to produce identical hash contributions. An attacker who knows a victim\u0027s username can bypass Digest authentication by replacing all non-Latin-1 characters in the password with `?` characters, since the collision password produces the same MD5-based Digest response hash as the original password.\n\n### Details\n### Root Cause\n\nIn `jetty-core/jetty-client/src/main/java/org/eclipse/jetty/client/DigestAuthentication.java`, the `apply()` method computes the three Digest auth hashes (H(A1), H(A2), and the final response) using ISO-8859-1 character encoding:\n\n```java\n// Line 171 \u2014 H(A1)\nString hashA1 = toHexString(digester.digest(a1.getBytes(StandardCharsets.ISO_8859_1)));\n\n// Line 179 \u2014 H(A2)\nString hashA2 = toHexString(digester.digest(a2.getBytes(StandardCharsets.ISO_8859_1)));\n\n// Line 196 \u2014 Final response hash\nfinal String hashA3 = toHexString(digester.digest(a3.getBytes(StandardCharsets.ISO_8859_1)));\n```\n\nISO-8859-1 (Latin-1) can only encode characters in the range U+0000\u2013U+00FF. Any character outside this range \u2014 including all CJK, Cyrillic, Arabic, Greek, Hangul, and emoji characters \u2014 is silently replaced with the byte `0x3F` (`?`). `String.getBytes(ISO_8859_1)` in Java performs this replacement without any warning or exception.\n\n### PoC\n```\nPassword: \"\u6211\u7231Java!\u5bc6\u7801123\u2605\" (7 non-Latin-1 characters)\n\nUTF-8 encoding:    45 bytes \u2192 MD5 H(A1) = 9a4e61484f228633d5d0f95d1bbb0a99\nISO-8859-1:        31 bytes \u2192 MD5 H(A1) = d60ddc903d71913bcc3ab4a94f7fc239\nCollision \"??...\": 31 bytes \u2192 MD5 H(A1) = d60ddc903d71913bcc3ab4a94f7fc239 \u2190 IDENTICAL\n```\n\nMulti-language confirmation \u2014 all four language passwords below produce the same hash:\n\n```\nChinese (\u5bc6\u7801123)  \u2192 H(A1) = db87f31e8d96cd15f9acec7eabdc4560\nKorean  (\ube44\ubc88123)  \u2192 H(A1) = db87f31e8d96cd15f9acec7eabdc4560\nCyrillic(\u0430\u0431123)    \u2192 H(A1) = db87f31e8d96cd15f9acec7eabdc4560\nGreek   (\u03b1\u03b2123)    \u2192 H(A1) = db87f31e8d96cd15f9acec7eabdc4560\nAttacker(??123)    \u2192 H(A1) = db87f31e8d96cd15f9acec7eabdc4560 \u2190 all collide!\n```\n\n### Impact\n**Scenario 1: Authentication Bypass (Collision Attack)**\n\nIf a service using Jetty for Digest authentication has a user with a non-Latin-1 password (e.g., Chinese, Japanese, Russian), an attacker can authenticate as that user using a collision password where all non-Latin-1 characters are replaced with `?`:\n\n- Original password: `\u6211\u7231Java!\u5bc6\u7801123\u2605`\n- Collision password: `??Java!??123?`\n- **Both produce identical MD5 hashes under ISO-8859-1** \u2192 Authentication succeeds\n\nThis affects any password containing characters \u003e U+00FF, which covers:\n- Chinese (CJK): U+4E00\u2013U+9FFF\n- Japanese (Hiragana/Katakana/Kanji): U+3040\u2013U+30FF, U+4E00+\n- Korean (Hangul): U+AC00\u2013U+D7AF\n- Cyrillic: U+0400\u2013U+04FF (Russian, Ukrainian, Bulgarian, etc.)\n- Arabic: U+0600\u2013U+06FF\n- Greek: U+0370\u2013U+03FF\n- Latin Extended: U+0100\u2013U+024F (accented European characters like \u0109, \u011f, \u00f1 when \u003e U+00FF)\n- Emoji / Symbols \u003e U+00FF\n\n**Scenario 2: Denial of Service for Non-Latin-1 Users**\n\nMost modern web applications store password hashes computed using UTF-8. When Jetty\u0027s Digest client computes a hash with ISO-8859-1, the bytes differ from what the server stored/expects. This means **any user with non-ASCII (Latin-1+) characters in their password can never successfully authenticate via Digest auth** \u2014 even the legitimate user. This is not just a security issue but a functional correctness bug that silently breaks authentication for most non-European-language users.",
  "id": "GHSA-2fvj-hgj9-j2gr",
  "modified": "2026-07-22T22:55:19Z",
  "published": "2026-07-22T22:55:18Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/jetty/jetty.project/security/advisories/GHSA-2fvj-hgj9-j2gr"
    },
    {
      "type": "WEB",
      "url": "https://github.com/jetty/jetty.project/issues/15136"
    },
    {
      "type": "WEB",
      "url": "https://github.com/jetty/jetty.project/pull/15160"
    },
    {
      "type": "WEB",
      "url": "https://github.com/jetty/jetty.project/pull/15183"
    },
    {
      "type": "WEB",
      "url": "https://github.com/jetty/jetty.project/commit/4bcdbc7db387ce9e20e2c7571a7250280466221d"
    },
    {
      "type": "WEB",
      "url": "https://github.com/jetty/jetty.project/commit/d0bb829ccecbf19e3ad3d32f2649b2800f01222d"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/jetty/jetty.project"
    },
    {
      "type": "WEB",
      "url": "https://github.com/jetty/jetty.project/releases/tag/jetty-12.0.36"
    },
    {
      "type": "WEB",
      "url": "https://github.com/jetty/jetty.project/releases/tag/jetty-12.1.10"
    }
  ],
  "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",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Eclipse Jetty Digest Authentication: ISO-8859-1 lossy encoding allows authentication bypass via character substitution"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Detection rules are retrieved from Rulezet.

Loading…

Loading…

Loading…