CVE-2026-54338 Overview
CVE-2026-54338 affects JupyterHub, a multi-user server platform for Jupyter notebooks. Versions prior to 5.5.0 accept unbounded attacker-controlled usernames in form-based login authenticators and write them verbatim to failed-login logs. An unauthenticated remote attacker can submit large or repeated login attempts to exhaust logging and storage resources. The issue is tracked under [CWE-400: Uncontrolled Resource Consumption] and is fixed in JupyterHub 5.5.0.
Critical Impact
Unauthenticated attackers can consume disk and logging capacity on JupyterHub servers by submitting oversized usernames to the login form, degrading service availability.
Affected Products
- JupyterHub versions prior to 5.5.0
- Deployments using form-based login authenticators (including PAM authenticator)
- Multi-user Jupyter notebook environments exposing the login endpoint
Discovery Timeline
- 2026-08-07 - CVE-2026-54338 published to NVD
- 2026-08-11 - Last updated in NVD database
Technical Details for CVE-2026-54338
Vulnerability Analysis
JupyterHub logs failed login attempts with the submitted username to aid administrators in identifying brute-force activity. The pre-5.5.0 implementation writes the raw username field from the login form directly into log records without any length bound or sanitization. Attackers who send login requests containing multi-megabyte username payloads cause the log writer to persist the entire input on each attempt.
Repeated abuse from a single attacker can fill disks, saturate log ingestion pipelines, and inflate storage costs on hosted deployments. The endpoint requires no authentication, so the attack surface is any network-reachable JupyterHub instance. The condition maps to [CWE-400] because the resource consumption scales with attacker input rather than server-side limits.
Root Cause
The logging paths in jupyterhub/auth.py and jupyterhub/handlers/base.py interpolate the submitted username into warning-level log messages without truncation. Because usernames are supplied through unauthenticated HTTP form data, the log entry size is bounded only by the HTTP body limit rather than by an application-level username policy.
Attack Vector
A remote unauthenticated attacker sends crafted POST requests to the JupyterHub login endpoint with an oversized username parameter and an invalid password. Each rejected attempt writes an attacker-controlled string to the JupyterHub log file. Sustained requests amplify disk usage, log rotation churn, and downstream SIEM ingestion.
# Security patch in jupyterhub/auth.py - truncate invalid username before logging
encoding=self.encoding,
)
except pamela.PAMError as e:
+ # username failed login, don't log full invalid user input
+ log_username = username
+ if len(username) > 32:
+ log_username = f"{username[:16]}...({len(username)} chars)"
if handler is not None:
self.log.warning(
- "PAM Authentication failed (%s@%s): %s",
- username,
+ "PAM Authentication failed (%r@%s): %s",
+ log_username,
handler.request.remote_ip,
e,
)
# Source: https://github.com/jupyterhub/jupyterhub/commit/d6dc595f84b7509969686da31d87d6d69e7fce0a
# Security patch in jupyterhub/handlers/base.py - truncate invalid username in base login handler
else:
self.statsd.incr('login.failure')
self.statsd.timing('login.authenticate.failure', auth_timer.ms)
- self.log.warning(
- "Failed login for %s", (data or {}).get('username', 'unknown user')
- )
+ log_username = username = (data or {}).get('username', 'unknown user')
+ # username failed login, don't log full invalid user input
+ if len(username) > 32:
+ log_username = f"{username[:16]}...({len(username)} chars)"
+ self.log.warning("Failed login for %r", log_username)
# Source: https://github.com/jupyterhub/jupyterhub/commit/d6dc595f84b7509969686da31d87d6d69e7fce0a
The fix truncates any username longer than 32 characters to a 16-character prefix plus a length indicator before it reaches the log formatter.
Detection Methods for CVE-2026-54338
Indicators of Compromise
- Rapid growth of JupyterHub log files or log-forwarding pipelines without a corresponding increase in legitimate user activity
- Log entries containing unusually long username strings in Failed login for or PAM Authentication failed warnings
- High volume of failed login POST requests to /hub/login from a single source IP
Detection Strategies
- Parse JupyterHub warning logs for Failed login events and alert when the extracted username exceeds a reasonable identity length (for example, 64 characters)
- Baseline log volume per JupyterHub instance and alert on sudden multi-standard-deviation increases in failed-login log line size
- Correlate web-tier request bodies exceeding expected login form size with subsequent authentication failures
Monitoring Recommendations
- Track disk utilization and inode consumption on hosts writing JupyterHub logs
- Forward JupyterHub logs to a centralized SIEM with rate limiting to prevent downstream storage exhaustion
- Instrument the login endpoint with request-size and per-IP request-rate metrics
How to Mitigate CVE-2026-54338
Immediate Actions Required
- Upgrade JupyterHub to version 5.5.0 or later on all Hub servers
- Place JupyterHub behind a reverse proxy that enforces a small maximum body size on /hub/login
- Apply rate limiting to unauthenticated login endpoints to bound resource consumption per source IP
- Rotate and cap the size of JupyterHub log files to prevent single-incident disk exhaustion
Patch Information
The fix is included in JupyterHub 5.5.0 and is implemented in commit d6dc595f84b7509969686da31d87d6d69e7fce0a. See the JupyterHub Security Advisory GHSA-p43p-whwx-q52h and the upstream commit for details. The patch truncates usernames longer than 32 characters before they are written to log records.
Workarounds
- Enforce a maximum request body size for the login endpoint at the reverse proxy or ingress layer
- Configure logrotate with strict size and maxsize limits on JupyterHub log files
- Restrict network access to the JupyterHub login endpoint to trusted networks or an authenticating proxy where feasible
# Example nginx reverse proxy configuration limiting login request size
location /hub/login {
client_max_body_size 4k;
limit_req zone=jupyter_login burst=5 nodelay;
proxy_pass http://jupyterhub_upstream;
}
# Example logrotate policy for JupyterHub logs
/var/log/jupyterhub/*.log {
size 50M
maxsize 100M
rotate 7
compress
missingok
notifempty
}
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

