# Eclipse Jetty Digest Authentication: ISO-8859-1 lossy encoding allows authentication bypass via character substitution

Jetty's Digest client hashes credentials with ISO-8859-1, silently mapping all chars >U+00FF to '?', so a collision password authenticates as users with non-Latin-1 passwords.

- Payout: Research
- Severity: high
- Program: Eclipse Jetty
- Found by (vendor credit): https://github.com/hrykx-zy
- Found by: hrykx-zy
- Disclosed: 2026-07-22
- CVE: CVE-2026-10050
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-2fvj-hgj9-j2gr
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-2fvj-hgj9-j2gr
- Tags: area:web domain:web impact:ato kind:research platform:ghsa sev:high tech:java technique:source-review technique:unicode-normalization vuln:auth-bypass vuln:crypto

**Target:** HTTP client Digest authentication (DigestAuthentication.apply)
**Root cause:** DigestAuthentication.apply() computes H(A1), H(A2) and the response hash via getBytes(ISO_8859_1), which silently replaces every character above U+00FF with 0x3F ('?'), collapsing distinct passwords to identical byte sequences.
**Steps:**
1. Identify a victim username whose password contains characters > U+00FF (CJK, Cyrillic, Greek, Arabic, emoji).
2. Construct a collision password by replacing every non-Latin-1 character with `?` (e.g. `我爱Java!密码123★` → `??Java!??123?`).
3. Authenticate with the collision password; Jetty's client encodes both to the same ISO-8859-1 bytes, producing identical MD5 H(A1) and response hash.
4. Server accepts the Digest response as valid for the victim.
**How found:** Code review of DigestAuthentication.apply() spotted getBytes(StandardCharsets.ISO_8859_1) at three hash sites; recognized Java's silent replacement of out-of-range chars with 0x3F and tested multi-language passwords to confirm hash collisions.
**Exploitation:** Attacker who knows a username and that the password contains non-Latin-1 characters submits a Digest response computed from the '?'-substituted password; identical MD5 hashes cause the server to accept it as the legitimate user.
**Insight:** When auditing auth code, check the charset used for hashing/encoding: any lossy single-byte charset (ISO-8859-1, ASCII) silently folds all out-of-range Unicode to a fixed byte, turning distinct secrets into hash collisions — grep for getBytes with non-UTF-8 charsets in credential paths.

## Proof of concept (copied exactly from the original report)

**Collision password producing identical H(A1) hash**

```
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 passwords all colliding to 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!
```

