CVE-2026-63202

HIGHPre-NVD 7.57.5
EchelonGraph scoreLOW confidence

This high-severity CVE scores 7.5 under the CNA's CVSS (NVD's own analysis pending). EPSS exploit-prediction score not yet available (the EPSS model rescores nightly; freshly-published CVEs typically appear within 48 hours). GitHub Security Advisory data not yet ingested — confidence will rise once GHSA publishes (typical lag: hours to days for open-source ecosystem CVEs; never for infrastructure-only CVEs).

Triggered by: NVD CVSS baseline
Sources: cna:github_m
7.5EG
EchelonGraph verdictPlan a fixSerious severity, but no confirmed exploitation yet.
  • High severity, but no confirmed exploitation yet
CISA-KEV: Not listedEPSS PROB: —CVSS: 7.5Exploit: None knownExposed services: Not assessed

A fix is available — apply it.

netty-incubator-codec-ohttp BinaryHttpParser: Unauthenticated CPU-exhaustion DoS via infinite loop in field-section decoding

BinaryHttpParser: Unauthenticated CPU-exhaustion DoS via infinite loop in field-section decoding

  • ID: BHTTP-LOOP-001
  • Severity: High
  • CVSS v3.1: 7.5 — CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
  • CWE: CWE-835 (Loop with Unreachable Exit Condition) — secondary CWE-400 (Uncontrolled Resource Consumption)
  • Affected component: codec-bhttp → io.netty.incubator.codec.bhttp.BinaryHttpParser#readFieldSection, file codec-bhttp/src/main/java/io/netty/incubator/codec/bhttp/BinaryHttpParser.java:619-626
  • Affected version: netty-incubator-codec-ohttp HEAD d3f2b49 (release 0.0.22.Final + 3 commits). The loop has existed since the parser was introduced and is present in the latest code; all published advisory fixes are already applied.
  • Reachable from: io.netty.incubator.codec.ohttp.OHttpRequestResponseContext$ContentDecoder#decodeChunk (codec-ohttp/.../OHttpRequestResponseContext.java:214), i.e. the auto-wired OHTTP server and client codecs.
  • Confidence: High (empirically reproduced hang + thread dump against the unmodified parser).

Summary

BinaryHttpParser decodes Binary HTTP (RFC 9292) messages. An OHTTP gateway/client built on this library feeds the decrypted OHTTP body straight into BinaryHttpParser.parse(...). The field-section decoding loop terminates only on the exact condition fieldSectionLength != 0 and relies on a Java assert to guarantee forward progress. Because (a) the loop counter can be driven negative and (b) readFieldLine(...) legitimately consumes zero bytes and returns null on a truncated/over-long field line, the loop can spin forever. Assertions are disabled in any normal production JVM, so the two assert statements meant to catch this provide no protection.

A single ~17-byte Binary HTTP message — encapsulated by an unauthenticated attacker inside a normal OHTTP request, using the gateway's public key configuration — pins one Netty event-loop thread at 100% CPU permanently. A handful of such requests exhausts the entire event-loop group and takes the OHTTP gateway (or client) fully offline.

Root cause

BinaryHttpParser.java:619-626:

HeaderType lastType = HeaderType.PSEUDO_HEADER;
while (fieldSectionLength != 0) {            // 619  — "!= 0", not "> 0"
    int readableBytes = in.readableBytes();
    lastType = readFieldLine(in, headers, lastType, trailers);
    assert lastType != null;                 // 622  — no-op without -ea
    int read = readableBytes - in.readableBytes();
    assert read > 0;                         // 624  — no-op without -ea
    fieldSectionLength -= read;              // 625
}

Two cooperating defects:

  • Counter can never hit zero. fieldSectionLength is the *declared* field-section byte length read from the wire (line 592). The loop subtracts the bytes each readFieldLine actually consumes. If a field line consumes more bytes than the (attacker-understated) declared length, fieldSectionLength goes negative and != 0 stays true forever.
  • Zero-progress iterations. readFieldLine (lines 654-707) returns null without consuming any bytes when the remaining buffer cannot hold a complete field line — at lines 656, 664, 670, and 681 (the in.skipBytes(sumBytes) that advances the reader is only reached on the success path, line 705). When it returns null, read == 0, fieldSectionLength is unchanged, and the loop re-enters with identical state — a tight busy spin.

The only constructs that would have stopped either case are the assert statements on lines 622 and 624, which the JVM strips unless started with -ea. Production deployments do not run with assertions enabled.

Reachability (hop-by-hop, every guard resolved)

Attacker model: OHTTP gateways publish their HPKE key configuration so that *any* client can encrypt requests to them. The attacker therefore encrypts a malicious BHTTP body under the gateway's public key — a perfectly valid OHTTP request. HPKE decapsulation succeeds; the plaintext is attacker-chosen.

  • OHttpServerCodec.decode → OHttpRequestResponseContext.parse → chunk decode → ContentDecoder.decodeChunk.
  • OHttpRequestResponseContext.java:211 decrypts the chunk into decryptedChunk; line 212 cumulates it; line 214 calls binaryHttpParser.parse(binaryHttpCumulation, completeBodyReceived) — attacker-controlled plaintext, no application code in between.
  • parse → READ_KNOWN_LENGTH_REQUEST_HEAD → readRequestHead (line 190).
  • readRequestHead reads the control data, then at lines 445-451 slices all remaining readable bytes as the field section and calls readFieldSection(..., knownLength=true, maxFieldSectionSize).
  • Inside readFieldSection:
  • Guard checkFieldSectionTooLarge(fieldSectionLength, max) (line 607): bounds only the *declared* length, which the PoC sets to 1. Passes — not a barrier.
  • Guard in.readableBytes() < sumBytes (line 609): sumBytes is built from the *declared* length, also tiny. Passes — not a barrier.
  • Guards assert (lines 622, 624): no-ops in production. Defeated by default.
  • Loop entered → spins forever (defects 1 + 2).

No reachable guard bounds the *actual* consumption or forces progress. maxFieldSectionSize is irrelevant because the declared length is small and the loop is CPU-bound on a fixed, small buffer (no allocation, no memory growth to trip any size cap).

Proof of concept (executed locally, benign liveness oracle)

The real codec-bhttp sources were compiled unmodified against netty 4.1.135.Final (the version pinned in pom.xml). The harness builds a valid known-length BHTTP request whose declared field-section length (0x01) is understated relative to the actual field line, then calls parse(in, true) on a worker thread with a 6-second watchdog. No payload, no side effects — purely a timing/CPU oracle.

Malicious message (17 bytes):

00 01 67 01 68 01 61 01 70 01 01 61 01 62 01 63 01
│  └method g └scheme h └auth a └path p │  └hdr a:b──┘ └ partial line
└ framing 0 (known-length request)     └ declared field-section length = 1

Observed (production default, assertions OFF):

[*] malicious BHTTP bytes (17): 0001670168016101700101610162016301
[!!] HANG CONFIRMED: parse() still running after 6000 ms
[!!] worker thread CPU time: 6029 ms (≈100% of one core => busy spin)
[!!] worker stack (top frames):
        at io.netty.incubator.codec.bhttp.BinaryHttpParser.readFieldSection(BinaryHttpParser.java:626)
        at io.netty.incubator.codec.bhttp.BinaryHttpParser.readRequestHead(BinaryHttpParser.java:451)
        at io.netty.incubator.codec.bhttp.BinaryHttpParser.parse(BinaryHttpParser.java:190)
CPU time ≈ wall time ⇒ a busy spin (RUNNABLE), not a blocked wait.

Controls:

  • Same input with -ea: parse() throws AssertionError at readFieldSection:624 immediately — proving the assertion is the only would-be guard and is absent in production.
  • Well-formed request (declared length matches): parse() returns DefaultBinaryHttpRequest promptly — proving the harness does not hang on valid input.

PoC sources: findings/netty-incubator-codec-ohttp/raw/Poc.java (hang + control 1) and raw/Poc2.java (negative control).

Impact

Unauthenticated, pre-business-logic remote denial of service. Each malicious request permanently consumes one Netty event-loop thread at 100% CPU. Netty event-loop groups have a small fixed thread count (default 2 × cores); a handful of requests exhausts every I/O thread, after which the gateway/client accepts no further connections and serves no traffic — a complete, persistent DoS that survives until process restart. Availability impact High; no confidentiality/integrity impact.

Adversarial re-reading (attempts to refute)

  • *"maxFieldSectionSize caps it."* No — the declared length in the PoC is 1; the cap (line 607) checks the declared value only. The spin happens on a 17-byte buffer with no allocation. Refutation fails.
  • *"An upstream HTTP size limit / HttpObjectAggregator blocks it."* No — the bug is CPU-bound, not memory-bound. The whole malicious message is tiny and well within any size limit. Refutation fails.
  • *"This is just CVE-2024-40642 (absent input validation)."* No — that advisory was about missing validation of method/scheme/authority/path enabling injection; that fix (the ALLOWED_TOKEN/ALLOWED_SCHEME validators, lines 76-122/461-466) is present and unrelated. This is a control-flow/termination defect in field-section length accounting. Distinct class, distinct code.
  • *"The hang might be a harness artifact."* No — the thread dump pinpoints readFieldSection:626; CPU≈wall confirms a spin; the -ea control throws at the exact assert; the well-formed control returns. The hang is for the claimed reason.
  • *"completeBodyReceived must be true."* Not required — the loop is inside readFieldSection, reached via readRequestHead once the control data is present, independent of that flag. The flag only affects a branch taken *after* readRequestHead returns null, which never happens here.

No concrete blocker survived. Verdict: CONFIRMED.

Remediation

  • Change the loop exit condition to while (fieldSectionLength > 0) so an overshoot (negative counter) terminates.
  • Treat a null / zero-progress return from readFieldLine while fieldSectionLength > 0 as a hard framing error — throw CorruptedFrameException("truncated or over-long field line") instead of re-looping.
  • Reject any field line whose consumed byte count would drive fieldSectionLength below 0 (the declared length must be consumed exactly, per RFC 9292 §3.6).
  • Do not rely on assert for wire-format invariants on attacker-controlled input; assertions are disabled in production. Promote lines 622/624 to explicit exceptions.

Example:

while (fieldSectionLength > 0) {
    int readableBytes = in.readableBytes();
    lastType = readFieldLine(in, headers, lastType, trailers);
    int read = readableBytes - in.readableBytes();
    if (lastType == null || read <= 0) {
        throw new CorruptedFrameException("truncated or over-long field line");
    }
    if (read > fieldSectionLength) {
        throw new CorruptedFrameException("field line exceeds declared field-section length");
    }
    fieldSectionLength -= read;
}

Notes

  • The indeterminate-length field-section path (framing indicators 2/3) shares the same loop and the same != 0 / zero-progress structure; the fix above should cover both. A dedicated trace of getIndeterminateLength (lines 538-566) under non-default maxFieldSectionSize is recorded separately as a lead.
  • Default maxFieldSectionSize for the OHTTP codecs is 8 * 1024 (OHttpCodecBuilder.DEFAULT_MAX_FIELD_SECTION_SIZE), and is irrelevant to this CPU-bound spin.

CVSS v3
7.5
EG Score
7.5HIGHlow confidence
EG Risk
38
EG Risk 38/100CISA SSVC

EG Risk is EchelonGraph's 0–100 priority score: it fuses intrinsic severity with real-world exploitation and automatability so you can rank equal-severity CVEs and fix the most dangerous first. Higher = act sooner. Distinct from the 0–10 EG Score (severity).

How it’s computed
Severity75% × 45%
Exploitation0% × 40%
Automatability30% × 15%
CISA SSVC: Track at low or medium mission impact; Track or Attend at high (mission-essential systems).
Action: A fix is available. Apply it within your standard update timelines at low or medium mission impact and sooner than that at high.
EPSS PROB
—
EPSS %ILE
—
KEV
Not listed

CISA SSVCTrack at low or medium mission impact; Track or Attend at high (mission-essential systems).

A fix is available. Apply it within your standard update timelines at low or medium mission impact and sooner than that at high.

Exploitation none (no KEV listing, exploit record or EPSS ≥ 50%) · Automatable unknown (not published for this CVE) · Technical impact partial (CVSS below 9.0). Mission impact is CISA's Mission & Well-being decision point, and only you can judge it: high means the affected system is essential to your organisation's mission, or its compromise could cause irreversible harm to people. CISA's decision table

Published

August 20, 2026

Last Modified

August 20, 2026

Vendor Advisories for CVE-2026-63202(1)

These vendors published their own advisory mentioning this CVE — often with vendor-specific remediation steps + affected product lists not in NVD.

Affected Packages

(1 across 1 ecosystem)
Maven(1)
PackageVulnerable rangeFix by version rangeDependents
io.netty.incubator:netty-incubator-codec-bhttp0.0.1.Final ... 0.0.9.Final (22 versions)
  • every version up to 0.0.23.Final: fixed in 0.0.23.Final
—

Data Freshness Timeline

(refreshed 0× in last 7d / 1× in last 30d)

Each row is a source pipeline that fetched or updated this CVE on that date, with what changed. For example, "NVD update" means NVD published or revised its analysis for this CVE; "MITRE cvelistV5" means we ingested or refreshed it from the CNA feed. Most recent first.

  1. 2026-09-28 23:58 UTCEG score recompute
  2. 2026-08-20 19:42 UTCEG score recompute

Same product

4 shown

Maven:io.netty.incubator:netty-incubator-codec-bhttp

Frequently asked(4)

What is CVE-2026-63202?
CVE-2026-63202 is a high vulnerability published on August 20, 2026. netty-incubator-codec-ohttp BinaryHttpParser: Unauthenticated CPU-exhaustion DoS via infinite loop in field-section decoding BinaryHttpParser: Unauthenticated CPU-exhaustion DoS via infinite loop in field-section decoding ID: BHTTP-LOOP-001 Severity: High CVSS v3.1: 7.5 —…
When was CVE-2026-63202 disclosed?
CVE-2026-63202 was first published on August 20, 2026. EchelonGraph re-ingests CVE updates from NVD on a 2-hour cycle, so this page reflects the latest published state.
What is the CVSS score of CVE-2026-63202?
CVE-2026-63202 has a CVSS base score of 7.5 (the CNA's own assessment, by github_m; NVD's own analysis pending). The EG score is currently aggregating — additional source signals are being incorporated as they become available..
How do I remediate CVE-2026-63202?
A fix for CVE-2026-63202 is available: update to the fixed version the vendor names in its advisory. The vendor advisories EchelonGraph has for CVE-2026-63202 are linked in the Vendor Advisories panel on this page.

Dependency Blast Radius

See which npm, PyPI, Go, and Maven packages are affected by CVE-2026-63202

Explore →

Is Your Infrastructure Affected by CVE-2026-63202?

EchelonGraph automatically scans your cloud infrastructure and maps CVE exposure using blast radius analysis.