← Back to Feed CACHED · 2026-07-02 19:56:37 · CACHE_KEY CVE-2026-6330
CVE-2026-6330 · CWE-327 · Disclosed 2026-06-25

The ML-KEM ARM64 NEON ciphertext comparison only compares half of the input

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
Do you agree?
01 · The Real Story

A safe deposit box that checks only the first half of your fingerprint before handing over what's inside

ML-KEM (FIPS 203, the NIST post-quantum KEM formerly known as Kyber) relies on the Fujisaki-Okamoto transform to convert a CPA-secure PKE into an IND-CCA2 KEM. The core trick is *implicit rejection*: on decapsulation the recipient re-encrypts the derived message and does a constant-time, full-length compare against the received ciphertext; on any mismatch the KEM returns a pseudorandom key derived from a secret seed instead of failing. The wolfSSL ARM64 NEON code path only compared roughly the first half of the re-encrypted ciphertext bytes, so mutations in the untested tail were silently accepted as valid.

This is a legitimate cryptographic regression: half the ciphertext is effectively unauthenticated, which breaks the FO transform's chosen-ciphertext hardening. That said, the CVSS C:L/I:L/A:N framing is fair. To turn the flaw into recovered plaintext or key material an attacker needs (a) reuse of a long-lived ML-KEM private key across many decapsulations, (b) an oracle that reveals whether decapsulation *effectively succeeded* (via observable session establishment, key confirmation, or subsequent AEAD success), and (c) the target must be compiled with the NEON backend on ARM64. Vendor MEDIUM (6.3) matches reality — it's a real IND-CCA2 downgrade, not a break-the-ciphertext primitive.

"Broken FO rejection on ARM64 NEON is a real IND-CCA2 gap, but exploitation needs a chosen-ciphertext oracle and key reuse — vendor MEDIUM stands."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Identify a target using wolfSSL ML-KEM NEON on ARM64

Attacker fingerprints TLS 1.3 / IKEv2 / SSH endpoints negotiating a hybrid or pure ML-KEM group and correlates server banners, uname strings, or wolfSSL version fingerprints. Only the ARM64 NEON build path is affected — x86_64, generic C reference, and AVX2 backends compare the full ciphertext correctly. Tooling: nmap ssl-enum-ciphers, testssl.sh with PQ group probes.
Conditions required:
  • Target negotiates ML-KEM (X25519MLKEM768 or similar) with wolfSSL
  • Target is ARM64 with NEON build path enabled at compile time
  • Long-lived static ML-KEM keypair (not ephemeral per-connection)
Where this breaks in practice:
  • Most TLS/SSH deployments use *ephemeral* ML-KEM keys per handshake — no key reuse means no oracle to query
  • Popular wolfSSL ARM64 builds on cloud Graviton often use the C reference path unless NEON is explicitly enabled
  • No easy remote way to distinguish NEON build from generic build
Detection/coverage: Nessus/Qualys plugins for wolfSSL versions land within ~14 days of CVE; no network-side scanner can detect the NEON compile flag remotely.
STEP 02

Establish a chosen-ciphertext oracle

Attacker sends crafted ML-KEM ciphertexts where the *tail half* differs from a valid re-encryption but the head half matches. Under the bug, the buggy comparator returns EQUAL, so the decapsulator returns the *real* shared secret instead of the implicit-rejection pseudorandom fallback. The attacker distinguishes the two branches via whether the subsequent AEAD/session-key confirmation succeeds.
Conditions required:
  • Ability to send many handshake attempts against the same static keypair
  • Observable success/failure oracle from higher-layer protocol
  • Protocol does NOT terminate the key before AEAD confirmation
Where this breaks in practice:
  • Static ML-KEM keys are rare — TLS 1.3 and IKEv2 profiles use per-handshake keys
  • Rate-limiting, IDS anomaly detection, and connection accounting flag high-volume handshake anomalies
  • Most deployed cryptographic protocols apply a KDF and transcript hash over the shared secret, which further blinds partial-ciphertext queries
Detection/coverage: WAF/IDS rules on ClientHello volume and repeated handshake failures from same source catch bulk probing.
STEP 03

Mount a chosen-ciphertext attack against the underlying K-PKE

With a working oracle that answers 'does this ciphertext decrypt to the same shared secret as my base ciphertext', the attacker runs a Kyber-style CCA attack (reaction-attack literature from Guo/Johansson and D'Anvers et al.) to recover the long-term secret key coefficient by coefficient. Requires on the order of 10^4–10^6 queries per key depending on failure-boundary geometry.
Conditions required:
  • Stable oracle from step 2
  • Same static key across the full query campaign
  • No handshake accounting or replay window that trips before enough queries land
Where this breaks in practice:
  • Query budget of millions of TLS handshakes against one endpoint is loud and slow
  • Any key rotation invalidates the campaign
  • Server-side anti-DoS (per-source rate limiting, TLS handshake accounting) breaks the campaign long before completion
Detection/coverage: Volumetric NetFlow / TLS handshake anomaly detection — this looks like a Kyber Bleichenbacher and stands out in NetFlow at 10^5+ handshakes/hour.
STEP 04

Recover session key or private key material

On success, attacker either (a) recovers a single session's shared secret and decrypts recorded traffic, or (b) recovers the ML-KEM private key and can decrypt all past and future traffic protected by that key. Impact depends entirely on whether the key was ephemeral or long-lived.
Conditions required:
  • Attack completes before key rotation
  • Traffic of interest was recorded or is being recorded
Where this breaks in practice:
  • Ephemeral-only deployments have nothing to recover after the handshake
  • Hybrid X25519+ML-KEM handshakes still require breaking X25519 to fully compromise traffic
Detection/coverage: Post-hoc: unusual decryption or MITM behavior on subsequent sessions.
03 · Intelligence Metadata

The supporting signals.

In-the-wild exploitationNone observed. No campaigns, no honeypot hits, no incident reports. This is a cryptographic implementation bug, not a network-reachable RCE.
Public PoCNo public exploit code. The C2SP/CCTV ML-KEM test vector suite catches this class of bug and was likely the discovery vector.
EPSS0.0013 (~0.13 percentile) — negligible predicted exploitation.
KEV statusNot listed. CISA KEV inclusion is unlikely absent in-the-wild proof.
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N = 6.3 MEDIUM. C:L/I:L correctly captures 'partial confidentiality/integrity loss under CCA', not full key recovery.
Affected componentwolfSSL ML-KEM implementation, ARM64 NEON backend only. Generic C, AVX2, and non-ARM64 builds are unaffected.
Fixed versionwolfSSL fix landed in the release following 2026-06-25 disclosure — see wolfSSL advisory for the exact tag; distros should ship backports within 1-2 weeks.
Disclosure2026-06-25, CVE assigned by wolfSSL as CNA.
ReporterDiscovered via ML-KEM implementation testing (C2SP/CCTV vectors and internal wolfSSL crypto review).
Exposure populationSmall: ARM64 targets running wolfSSL with NEON-enabled ML-KEM and *static* (not ephemeral) keys. Most TLS 1.3 / IKEv2 deployments use ephemeral KEM keys — no oracle, no attack.
04 · The Call

noisgate verdict.

Final Verdict
= UNCHANGED to MEDIUM (5.8/10)

The single decisive factor is that practical exploitation requires a chosen-ciphertext oracle against a reused static ML-KEM keypair — a configuration that is rare in the dominant deployment patterns (TLS 1.3, IKEv2 hybrid), and even where present is heavily rate-limited. The IND-CCA2 downgrade is real and CVSS C:L/I:L accurately captures a partial-confidentiality flaw, not a break-the-ciphertext primitive.

HIGH Assessment that the bug is a real IND-CCA2 regression
MEDIUM Estimate of exploitable installed base (depends on how many wolfSSL deployments reuse ML-KEM keys)
HIGH Confidence that no active exploitation exists

Why this verdict

  • Chosen-ciphertext oracle required — attacker needs to observe decapsulation success/failure across many crafted ciphertexts. TLS 1.3 KDF and transcript hashing blind the oracle in the dominant PQ profile.
  • Static key reuse required — ephemeral ML-KEM keys (the default in TLS 1.3 hybrid groups and IKEv2) eliminate the attack surface entirely. Only long-lived KEM keypairs (some IoT / VPN / bespoke messaging profiles) are exposed.
  • Narrow build target — only wolfSSL ARM64 NEON path. x86_64, generic C, and AVX2 builds compare full ciphertext correctly.
  • Role multiplier: identity/PKI role — wolfSSL is used inside some VPN concentrators and embedded IdP/certificate proxies. If one of these reuses a static ML-KEM key, chain outcome is session-key or long-term-key recovery. However, wolfSSL's ML-KEM deployment is still overwhelmingly ephemeral-key TLS 1.3, so the high-value-role installed base share is well below the 1% CRITICAL floor threshold.
  • Role multiplier: embedded / IoT typical role — wolfSSL's dominant footprint is embedded devices where TLS handshakes may be volumetrically low and keys sometimes long-lived. Chain succeeds in theory, but query budgets of 10^5+ handshakes against a device are impractical and detectable.
  • No amplifier evidence — EPSS 0.0013, no PoC, no KEV, no in-the-wild reports.

Why not higher?

HIGH would require either broad KEM-key-reuse deployments, a demonstrated efficient oracle in a common protocol profile, or active exploitation evidence. None of those exist today: TLS 1.3 and IKEv2 use ephemeral keys, the CCA query budget is enormous, and no PoC or campaign has surfaced.

Why not lower?

LOW / IGNORE is wrong because this is a genuine break of the FO transform's IND-CCA2 property on a real deployed code path, and there are wolfSSL profiles (embedded VPN, some messaging stacks) that DO reuse ML-KEM keys. Anywhere key reuse exists, the vendor's C:L/I:L framing understates the ceiling — full-key recovery is the theoretical endpoint.

05 · Compensating Control

What to do — in priority order.

  1. Disable the ARM64 NEON ML-KEM backend and fall back to generic C — Rebuild wolfSSL with --disable-armasm or unset WOLFSSL_ARMASM_CRYPTO_MLKEM on ARM64 targets until the patched version is deployed. Ship this within the 365-day remediation window; there is no noisgate mitigation SLA for MEDIUM verdicts.
  2. Force ephemeral ML-KEM keys in every protocol profile you control — In TLS 1.3, ensure the hybrid group is negotiated per-handshake (default in mainline profiles). In IKEv2 with PQ additional key exchanges, verify KEM keys are not cached across SAs. Ephemeral key use eliminates the oracle entirely.
  3. Rate-limit and alert on repeated PQ handshake failures from a single source — The chosen-ciphertext attack needs 10^4–10^6 queries against one key. Standard TLS/IKE handshake anti-abuse (per-IP throttling, cookie challenges, failure-rate alerts) neutralizes the query budget.
  4. Inventory static ML-KEM key usage across VPN, messaging, and embedded fleets — Ask each product team: *does this deployment cache or persist an ML-KEM keypair across sessions?* Any 'yes' answer plus wolfSSL ARM64 NEON is your patch-first cohort.
What doesn't work
  • Rotating TLS server X.509 certs — the flaw is in the KEM ciphertext comparison, not in cert-based auth. Cert rotation does not rotate the ML-KEM keypair.
  • Enabling FIPS mode — this bug is in FIPS-relevant ML-KEM code, so FIPS validation status alone does not protect you.
  • WAF signatures on ClientHello — the malicious ciphertext bytes are indistinguishable at the byte level from valid ones; only volumetric anomaly detection helps.
06 · Verification

Crowdsourced verification payload.

Run this on each wolfSSL-linked host (ARM64 targets in particular). Invoke as sudo ./check_wolfssl_mlkem.sh — needs read access to /usr/lib, /usr/local/lib, and the ability to run wolfssl-config if installed. Reports VULNERABLE if a wolfSSL library on ARM64 is present at a pre-fix version with NEON support compiled in.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# noisgate: CVE-2026-6330 wolfSSL ML-KEM ARM64 NEON check
set -u
FIXED_MAJOR=5
FIXED_MINOR=8
FIXED_PATCH=0   # adjust to actual patched wolfSSL tag once published

arch=$(uname -m)
if [[ "$arch" != "aarch64" && "$arch" != "arm64" ]]; then
  echo "PATCHED (host arch $arch is not affected — NEON path is ARM64-only)"
  exit 0
fi

found=0
vuln=0
while IFS= read -r lib; do
  found=1
  # Extract version string from the shared object
  ver=$(strings "$lib" 2>/dev/null | grep -Eo 'wolfSSL [0-9]+\.[0-9]+\.[0-9]+' | head -1 | awk '{print $2}')
  if [[ -z "$ver" ]]; then
    echo "UNKNOWN wolfSSL version in $lib"
    continue
  fi
  IFS=. read -r MA MI PA <<< "$ver"
  # Check NEON ML-KEM symbol presence
  if nm -D "$lib" 2>/dev/null | grep -qiE 'mlkem.*neon|kyber.*neon|armasm.*mlkem'; then
    if (( MA < FIXED_MAJOR )) || \
       (( MA == FIXED_MAJOR && MI < FIXED_MINOR )) || \
       (( MA == FIXED_MAJOR && MI == FIXED_MINOR && PA < FIXED_PATCH )); then
      echo "VULNERABLE: $lib wolfSSL $ver (ARM64 NEON ML-KEM present, pre-fix)"
      vuln=1
    else
      echo "PATCHED: $lib wolfSSL $ver"
    fi
  else
    echo "PATCHED: $lib wolfSSL $ver (no NEON ML-KEM symbols)"
  fi
done < <(find /usr/lib /usr/local/lib /opt -name 'libwolfssl*.so*' 2>/dev/null)

if (( found == 0 )); then
  echo "UNKNOWN: no libwolfssl found on standard paths"
  exit 2
fi
exit $(( vuln ))
07 · Bottom Line

If you remember one thing.

TL;DR
Verdict is MEDIUM — patch it, but you have runway. Per the noisgate mitigation SLA for MEDIUM verdicts there is no mitigation deadline; go straight to the noisgate remediation SLA of ≤ 365 days for the actual wolfSSL upgrade. Monday morning: (1) query your SBOM for wolfSSL on ARM64 hosts and flag anything using ML-KEM; (2) confirm with product teams whether any of those flows reuse static ML-KEM keys — if yes, promote that subset to a 30-day patch cadence and disable NEON ML-KEM in the meantime; (3) push the wolfSSL upgrade through normal quarterly patch waves for the rest. Skip the panic — ephemeral-key TLS 1.3 and IKEv2 deployments are effectively immune.

Sources

  1. CVE-2026-6330 (THREATINT)
  2. CVE-2026-6330 (TheHackerWire)
  3. wolfSSL Security Vulnerabilities advisory index
  4. C2SP/CCTV ML-KEM test vector suite
  5. NIST FIPS 203 (ML-KEM specification)
  6. Failing gracefully: Decryption failures and the FO transform
  7. Binding Security of Implicitly-Rejecting KEMs
  8. filippo.io — Post-quantum Cryptography for the Go Ecosystem (background on ML-KEM CCA)
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.