GCVE Workshop - 22 September 2026 (14:00-18:00), Luxembourg Before The Vulnopticon Conference - Registration

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…

Related by attack behaviour

Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.


Loading…