CVE-2026-69206 Overview
Http4s is a Scala interface for building HTTP services. Versions prior to 0.23.35 and 1.0.0-M47 contain a flaw in the DigestAuth middleware replay protection logic. The NonceKeeper component stores lastNc + 1 instead of the highest accepted nonce-count (nc) value. When legitimate clients issue noncontiguous nc values due to parallel or retried requests, the stored counter falls below the accepted maximum. A passive network observer can then replay a captured Authorization header multiple times to execute authenticated requests, including state-changing operations, as the captured user. The issue is categorized as [CWE-294] Authentication Bypass by Capture-replay.
Critical Impact
A passive observer capturing a single Digest Authorization header can replay it to perform authenticated actions, including state-changing operations, as the victim user.
Affected Products
- Http4s versions prior to 0.23.35
- Http4s 1.0.0 milestone releases prior to 1.0.0-M47
- Applications using the DigestAuth server middleware
Discovery Timeline
- 2026-09-15 - CVE-2026-69206 published to NVD
- 2026-09-16 - Last updated in NVD database
Technical Details for CVE-2026-69206
Vulnerability Analysis
HTTP Digest Access Authentication uses a per-request nonce-count (nc) value that must strictly increase to prevent replay of captured Authorization headers. The Http4s server middleware tracks the last accepted nc per nonce in a NonceKeeper structure. The comparison logic accepted any request where the incoming nc exceeded the stored value, but then updated the stored value to lastNc + 1 rather than the incoming nc. Clients issuing parallel or retried requests naturally skip values (for example, nc=1, 3, 5), leaving the stored counter well below the maximum accepted value. An attacker who captured a request with a higher nc could replay it repeatedly as long as the stored counter remained below the captured nc.
Root Cause
The defect resides in NonceKeeper.scala and NonceKeeperF.scala under server/shared/src/main/scala/org/http4s/server/middleware/authentication/. The replay-protection invariant requires that the stored counter equal the maximum accepted nc. Storing lastNc + 1 violates this invariant whenever accepted nc values are noncontiguous, effectively creating a replay window between the stored counter and the highest observed nc.
Attack Vector
Exploitation requires the attacker to passively observe a valid Digest Authorization header on the network, which implies transport without TLS or on a compromised path. The attacker must then race legitimate clients whose noncontiguous nc values leave the server counter below the captured request's nc. No user interaction or credentials are required, but the attack conditions elevate complexity. Successful replays execute authenticated requests server-side as the captured user.
// Patch: server/shared/src/main/scala/org/http4s/server/middleware/authentication/NonceKeeper.scala
// Store the maximum nc instead of previous+1
case null => NonceKeeper.StaleReply
case n: Nonce =>
if (nc > n.nc) {
- n.nc = n.nc + 1
+ n.nc = nc
NonceKeeper.OKReply
} else
NonceKeeper.BadNCReply
// Source: https://github.com/http4s/http4s/commit/7f065101c45f3d86bc105e8fc6323c2c4a11471f
// Patch: server/shared/src/main/scala/org/http4s/server/middleware/authentication/NonceKeeperF.scala
case n: NonceF[F] =>
n.nc.modify { lastNc =>
if (nc > lastNc) {
- (lastNc + 1, NonceKeeper.OKReply)
+ (nc, NonceKeeper.OKReply)
} else
(lastNc, NonceKeeper.BadNCReply)
}
// Source: https://github.com/http4s/http4s/commit/7f065101c45f3d86bc105e8fc6323c2c4a11471f
Detect Identity Attacks the Moment Authentication Fails
Singularity™ Identity surfaces credential misuse, lateral movement, and privilege escalation in real time, so you can contain the breach before it spreads.
Stop Identity AttacksDetection Methods for CVE-2026-69206
Indicators of Compromise
- Repeated successful Digest-authenticated requests reusing the same nonce and nc value from the same or different source addresses.
- Server access logs showing state-changing requests whose Authorization header cnonce and response fields exactly match a prior request.
- Sudden clusters of authenticated actions performed as a single user from unexpected IP addresses.
Detection Strategies
- Instrument the Http4s DigestAuth middleware to log accepted (nonce, nc) tuples and alert on duplicates.
- Inspect network capture or reverse-proxy logs for identical Authorization: Digest header values appearing across multiple requests.
- Correlate authenticated write operations with prior read requests bearing the same Digest credential material.
Monitoring Recommendations
- Track deployed Http4s versions across services and flag any instance below 0.23.35 or 1.0.0-M47.
- Enable audit logging for authentication events and forward to a centralized SIEM or data lake for replay-pattern analysis.
- Monitor for Digest authentication traffic traversing non-TLS channels, which enables passive header capture.
How to Mitigate CVE-2026-69206
Immediate Actions Required
- Upgrade Http4s to 0.23.35 (2.x line) or 1.0.0-M47 (1.0 milestone line) immediately.
- Enforce TLS on all endpoints protected by DigestAuth to prevent passive capture of Authorization headers.
- Rotate any credentials known or suspected to have been transmitted over unencrypted channels.
Patch Information
The fix updates both NonceKeeper and NonceKeeperF to store the incoming nc value rather than lastNc + 1, restoring the strictly-increasing invariant. Details are available in the GitHub Security Advisory GHSA-9xww-74xv-gjfp, the patch commit 7f065101, and the release notes for v0.23.35 and v1.0.0-M47.
Workarounds
- Replace DigestAuth middleware with a stronger scheme such as mutual TLS or token-based authentication over TLS until patching is complete.
- Terminate TLS at an upstream proxy so Digest Authorization headers cannot be captured on the wire.
- Shorten server-side nonce lifetimes to reduce the window during which a captured header remains replayable.
# sbt: pin patched Http4s versions in build.sbt
libraryDependencies ++= Seq(
"org.http4s" %% "http4s-server" % "0.23.35",
"org.http4s" %% "http4s-ember-server" % "0.23.35"
)
# For projects on the 1.0 milestone line:
# libraryDependencies += "org.http4s" %% "http4s-server" % "1.0.0-M47"
# Verify the resolved version
sbt "show dependencyTree" | grep http4s
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

