Jetty is a widely used Java-based web server and servlet engine, valued for its speed and flexibility. But in 2023, a significant vulnerability—CVE-2023-41900—was found in specific Jetty versions, posing a risk to systems using OpenID authentication. This post explains the vulnerability in simple language with example code, discusses how attackers could exploit it, and provides links to official references.
What Is CVE-2023-41900?
Jetty versions 9.4.21 through 9.4.51, 10..15, and 11..15 contain a weak authentication vulnerability in the OpenIdAuthenticator. This happens specifically when the OpenIdAuthenticator uses a nested LoginService.
In short: If a user was already authenticated and then the LoginService decided to reject (revoke) them on a later request, that same request would STILL be treated as authenticated. The rejection would only take effect on later requests. So, a user who was just revoked might be able to access what they shouldn't for one extra request.
How Does It Work?
- jetty-openid lets developers connect Jetty to an OpenID provider (e.g., Google Identity, Keycloak, etc).
- A LoginService can be nested within the OpenIdAuthenticator to add checks such as bans or revocations.
- If the LoginService revokes a user who was already authenticated, Jetty didn’t catch this immediately for the *current* request.
- The session is cleared for the following requests, but the *current* request may go through as if the user was still authorized.
Alice makes a request just after being banned.
4. The problem: That request goes through as if she was still logged in! After that, her session is killed, but it’s too late for this one action.
Let’s look at a simplified Java-like pseudocode to understand what happened internally
// Pseudo code inside Jetty OpenIdAuthenticator
if (userIsAuthenticated(session)) {
if (loginService.isUserAllowed(user)) {
// user is allowed, process request
proceed(request);
} else {
// user is NOT allowed, but...
// -- VULNERABILITY: the current request is still considered authenticated!
// In reality, the session is cleared only after this request.
proceed(request); // This should NOT happen!
clearAuthentication(session);
}
}
Fixed Workflow
if (userIsAuthenticated(session)) {
if (loginService.isUserAllowed(user)) {
proceed(request);
} else {
// Fix: immediately reject request and clear authentication
clearAuthentication(session);
rejectRequest();
}
}
Running the affected versions (9.4.21–9.4.51, 10..15, 11..15) AND
- Having a nested LoginService that can revoke users (e.g., blocklist/ban).
Potential Impact
- Users who should have been blocked can access or manipulate data/actions for *one more request*.
Official References
- CVE-2023-41900 Detailed Description
- Eclipse Jetty GitHub Security Advisory
- Jetty Issue Tracker - 924
- Upgrading Jetty
How to Fix It
Jetty versions 9.4.52, 10..16, and 11..16 or later include a patch. Just upgrade your Jetty server to one of these or a newer release.
Upgrade Sample with Maven
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>11..16</version>
</dependency>
Or with Gradle
implementation 'org.eclipse.jetty:jetty-server:11..16'
Conclusion
CVE-2023-41900 is a perfect example of a subtle but dangerous bug in session-based authentication. If using Jetty with OpenID and custom user services, check your version and upgrade immediately. Don’t let a "last chance" request become your biggest risk.
Stay safe! For the full CVE detail, see NIST NVD CVE-2023-41900.
If you have questions or want a deeper look into upgrading Jetty, check out Jetty’s official upgrade guide.
*Written for developers and admins who may not know they’re one request away from a problem!*
Timeline
Published on: 09/15/2023 21:15:11 UTC
Last modified on: 11/10/2023 18:15:08 UTC