← Back to Feed CACHED · 2026-10-02 15:19:43 · CACHE_KEY CVE-2026-6330
CVE-2026-6330 · CWE-327 · Disclosed 2026-06-25

wolfSSL ML-KEM ARM64 NEON Incomplete Ciphertext Comparison Breaks Fujisaki-Okamoto Implicit Rejection

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

Like a bank vault whose combination lock only checks half the digits, this NEON codepath lets an attacker brute-force the rest

CVE-2026-6330 is an implementation flaw in wolfSSL's hand-optimized ARM64 NEON assembly for ML-KEM (FIPS 203, formerly Kyber) decapsulation. An ins instruction was used where ext was intended, causing the constant-time ciphertext comparison in the Fujisaki-Okamoto re-encryption check to evaluate only ~784 of the 1,568 bytes of an ML-KEM-1024 ciphertext. The unchecked bytes encode compressed decryption noise that is a linear function of the secret key. An attacker who can submit chosen ciphertexts to a decapsulation oracle — e.g. a static ML-KEM key used in HPKE or KEMTLS — can recover 98.5% of the 2,048 secret coefficients with ~600 chosen ciphertexts and a total query budget of 10⁵–10⁶ decapsulations. Affected versions span wolfSSL 5.7.4 through 5.9.1 on ARM64 with NEON enabled; fixed in 5.9.2 (released June 23, 2026). Ephemeral TLS 1.3 hybrid handshakes, which generate a fresh ML-KEM key per session, are NOT vulnerable to key recovery — only to a distinguishing attack.

The vendor rated this MEDIUM 6.5 with a CVSS vector of AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N. That vector is objectively wrong: C:L/I:L for a vulnerability that enables full private-key recovery is indefensible. The corrected confidentiality impact is C:H at minimum — the attacker recovers the long-term secret key itself, not a partial data leak. wolfSSL likely scored this against the most common deployment pattern (ephemeral TLS 1.3, where key recovery doesn't apply), which is a defensible framing for *population-level* risk but badly misleads anyone running static ML-KEM keys in HPKE, KEMTLS, or pinned-key embedded deployments. The NEON bug was independently discovered by Nicholas Carlini of Anthropic; the related AVX2 bug (CVE-2026-10097) was found by Bhabani Sankar Das (@007bsd), who released full end-to-end key recovery code. This is not theoretical — the exploit works on shipped binaries.

"wolfSSL ML-KEM NEON bug enables full private-key recovery; vendor CVSS undersells catastrophic crypto impact"
02 · The Attack Path

4 steps from start to impact.

STEP 01

Identify a wolfSSL ML-KEM static-key endpoint on ARM64

The attacker locates a service using wolfSSL ≥5.7.4 and <5.9.2 on an ARM64 platform with NEON extensions enabled, offering ML-KEM key encapsulation with a reused (static) decapsulation key. Candidates include HPKE static recipients, KEMTLS servers with long-term KEM keys, or embedded/IoT devices with firmware-pinned keys. The ML-KEM NEON codepath is the default on ARM64 builds with SIMD support.
Conditions required:
  • Target runs wolfSSL 5.7.4–5.9.1 on ARM64 with NEON
  • Target uses a static (non-ephemeral) ML-KEM key
  • Attacker can reach the decapsulation endpoint over the network
Where this breaks in practice:
  • ML-KEM adoption is still early — most wolfSSL deployments use classical X25519/ECDH
  • Static ML-KEM key usage is rarer than ephemeral; TLS 1.3 hybrid mode is ephemeral by default
  • No Shodan/Censys fingerprinting exists to remotely identify wolfSSL ML-KEM endpoints
Detection/coverage: No scanner signatures exist to remotely identify vulnerable wolfSSL ML-KEM endpoints. Version detection requires banner analysis or firmware introspection.
STEP 02

Submit chosen ciphertexts to the decapsulation oracle

The attacker crafts approximately 600 ML-KEM-1024 ciphertexts that differ in the unchecked byte region (bytes the NEON comparison ignores). Each ciphertext probes different quantization levels of the compressed v-coefficients. The attacker initiates TLS/HPKE/KEMTLS sessions or API calls that invoke wc_MlKemDecapsulate() on the static key. A binary search over quantization thresholds for each unchecked coordinate is performed, requiring 10⁵–10⁶ total decapsulations.
Conditions required:
  • Ability to submit arbitrary ciphertexts for decapsulation against the same static key
  • Ability to observe whether decapsulation succeeded or produced implicit rejection (plaintext-checking oracle)
Where this breaks in practice:
  • 10⁵–10⁶ decapsulations is a large volume; rate limiting or anomaly detection could flag this
  • Some deployments may not expose a clear oracle signal distinguishing successful decapsulation from rejection
  • Protocol-level framing may limit ciphertext manipulation (though ML-KEM ciphertexts are opaque blobs)
Detection/coverage: Anomaly detection on decapsulation volume per key: 100,000+ operations against a single static key in a short window is abnormal. No specific IDS/IPS signature exists; custom rate-limiting on KEM operations would catch this.
STEP 03

Solve the linear system via ordinary least squares

The unchecked ciphertext bytes encode compressed tail coefficients of the decryption noise, which are exact linear forms of the secret key with known coefficients. The attacker collects measurement vectors from the binary-search oracle outputs and constructs a system of linear equations. Standard OLS regression (no lattice reduction needed) solves for 98.5% of the 2,048 secret coefficients. Remaining coefficients are recoverable with additional queries since measurement noise averages to zero. The attack uses the public PoC at github.com/007bsd/ml-kem-key-recovery.
Conditions required:
  • Successful oracle responses from step 2
  • Computational resources for OLS regression (trivial on a laptop)
Where this breaks in practice:
  • None — once oracle data is collected, key recovery is deterministic and fast
STEP 04

Recover full ML-KEM private key and decrypt past/future traffic

With 98.5%+ of the secret coefficients recovered, the attacker reconstructs the full ML-KEM-1024 private key. This enables decryption of any past ciphertext encapsulated to this static key (if captured) and future interception of all sessions using the compromised key. In HPKE scenarios, this breaks sender confidentiality for all messages to the static recipient. In KEMTLS, this enables impersonation of the server.
Conditions required:
  • Recovered secret coefficients from step 3
  • Captured ciphertexts (past or future) encapsulated to the compromised key
Where this breaks in practice:
  • If the deployment rotates keys frequently, past capture window is limited
  • If TLS 1.3 forward secrecy is layered on top, past session keys may be protected even if the KEM key is recovered
Detection/coverage: Post-compromise detection is extremely difficult — the attacker holds a valid private key clone. Key rotation or re-keying is the only remediation.
03 · Compensating Control

1
HIGH 7.5→IGNORE 0.0
SEVERITY REDUCED
Upgrade to wolfSSL 5.9.2 immediately on all ARM64 ML-KEM deployments — The definitive fix. wolfSSL 5.9.2 corrects the NEON instruction (ext replaces ins) so the full 1,568-byte ciphertext comparison is performed. Per noisgate HIGH remediation SLA, deploy within 180 days — but for any system actively using static ML-KEM keys, treat as emergency and patch within 3 days.
2
HIGH 7.5→HIGH 7.0
Rotate all static ML-KEM keys on affected systems — Any static ML-KEM key that was used for decapsulation on a wolfSSL 5.7.4–5.9.1 ARM64 NEON build must be considered potentially compromised. Generate new keypairs after upgrading to 5.9.2. This is especially critical for HPKE static recipients and KEMTLS server keys. Deploy within 30 days per noisgate mitigation SLA.
3
HIGH 7.5→LOW 3.0
SEVERITY REDUCED
Switch to ephemeral ML-KEM key exchange if static keys are not operationally required — Ephemeral TLS 1.3 hybrid handshakes generate a fresh ML-KEM key per session and are NOT vulnerable to key recovery (only a distinguishing attack applies). If your deployment can tolerate ephemeral keys, this eliminates the attack path entirely. Evaluate and deploy within 30 days.
4
HIGH 7.5→MEDIUM 5.5
SEVERITY REDUCED
Implement rate-limiting on KEM decapsulation operations — The attack requires 10⁵–10⁶ decapsulations against a single static key. Rate-limiting decapsulation calls per key to a threshold well below this (e.g., 1,000/hour) raises the practical bar significantly. This is a detection and friction control, not a fix. Deploy within 30 days per noisgate mitigation SLA.
5
HIGH 7.5→IGNORE 0.0
SEVERITY REDUCED
Disable NEON SIMD and fall back to reference C implementation — If upgrading is not immediately possible, recompiling wolfSSL without NEON acceleration (--disable-armasm) forces the reference C codepath, which performs the full ciphertext comparison correctly. This trades performance for correctness. Note: the AVX2 codepath (CVE-2026-10097) has a similar but separate bug — if cross-compiling, ensure neither SIMD path is used.
What doesn't work
  • WAF / IPS signatures — ML-KEM ciphertexts are opaque binary blobs inside TLS records; no WAF can distinguish a legitimate ciphertext from a crafted one. The attack operates within the normal protocol flow.
  • TLS inspection / decryption proxies — These break the end-to-end KEM handshake and would prevent the attack, but they also prevent PQC from functioning at all. This is not a compensating control; it's disabling the feature.
  • Network segmentation alone — While limiting attacker reach to the decapsulation endpoint helps, the attack is purely logical and works over any network path that reaches the service. Segmentation slows the attacker but does not prevent the key recovery once oracle access is obtained.
  • FIPS mode — wolfSSL's FIPS 140-3 validated modules (certificates #4718, #5041) do not include ML-KEM. The FIPS codepath is unaffected, but this is because it doesn't offer PQC, not because it mitigates the bug.
04 · Intelligence Metadata

The supporting signals.

In-the-Wild ExploitationNo confirmed in-the-wild exploitation. Not listed in CISA KEV. No GreyNoise or Shadowserver scanning activity observed. The attack requires static ML-KEM keys and sustained oracle access, making opportunistic exploitation unlikely.
Proof-of-ConceptPublic PoC available. Bhabani Sankar Das (@007bsd) released full end-to-end key recovery code at github.com/007bsd/ml-kem-key-recovery covering both AVX2 (CVE-2026-10097) and NEON (CVE-2026-6330) codepaths. The PoC includes oracle construction, ciphertext generation, and OLS key recovery scripts. A companion academic preprint is at eprint.iacr.org/2026/1682.
EPSS0.00169 (bottom ~15th percentile). Reflects the narrow exposure surface — ML-KEM adoption is early and the ARM64 NEON intersection is small. EPSS does not capture the catastrophic impact ceiling for affected deployments.
CVSS VectorCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N (vendor-assigned, 6.5 MEDIUM). The C:L/I:L ratings are objectively wrong for a full private-key recovery — the corrected vector should be at minimum C:H/I:H, yielding a base score of 9.1. The vendor likely scored against ephemeral TLS 1.3 usage where key recovery doesn't apply.
Affected VersionswolfSSL 5.7.4 through 5.9.1 on ARM64 with NEON SIMD. The NEON codepath was introduced in 5.7.4 (late 2024). The related AVX2 bug (CVE-2026-10097) affects 5.7.0–5.9.1 on x86-64. Earlier 5.7.x versions required --enable-experimental for ML-KEM, limiting exposure.
Fixed VersionwolfSSL 5.9.2 (released June 23, 2026). Fix commit: ac01707f552c611fbd135cc723b2682b3e7f80f2. PR #10192. Downstream: Debian and Ubuntu have tracking entries (DEBIAN-CVE-2026-6330, UBUNTU-CVE-2026-6330).
Scanning / ExposureNo Shodan, Censys, or FOFA fingerprints exist for wolfSSL ML-KEM endpoints. wolfSSL does not expose version strings in TLS handshakes by default. Remote identification requires firmware analysis or SBOM inspection. wolfSSL claims 5+ billion device installations across IoT, automotive, industrial, and government sectors.
ResearchersNicholas Carlini (Anthropic) independently discovered the NEON bug via Project Glaswing. Bhabani Sankar Das (@007bsd) discovered the AVX2 variant and published the PoC and preprint. Carlini previously found CVE-2026-5194 (critical wolfSSL cert verification flaw).
Related CVEsCVE-2026-10097 (AVX2 variant, rated HIGH by wolfSSL) — same class of bug on the x86-64 codepath, skipping the final 32 bytes. Both CVEs share the same root cause: incomplete FO re-encryption comparison in SIMD-optimized assembly.
PQC Deployment ContextML-KEM adoption is early but accelerating under CNSA 2.0 mandates (NSA target: 2030–2033 for national security systems). wolfSSL is the first CNSA 2.0-compliant embedded crypto provider. Static-key use cases (HPKE recipients, KEMTLS, embedded pinned keys) are the highest-risk deployments. Firmware update cycles for embedded devices are measured in quarters to years.

Sources.

  1. wolfSSL Security Vulnerabilities
  2. wolfSSL 5.9.2 Release (GitHub)
  3. Fix PR #10192
  4. PoC: ML-KEM Key Recovery (007bsd)
  5. Research Preprint (ePrint 2026/1682)
  6. wolfSSL ML-KEM Key Recovery Analysis (postquantum.com)
  7. OSV Entry: CVE-2026-6330
  8. Ubuntu CVE Tracker
05 · The Call

Final Verdict
↑ UPGRADED to HIGH (7.5/10)

Why this verdict

  • Understated CVSS vector: The vendor's C:L/I:L is objectively wrong for a full private-key recovery attack. The corrected impact is C:H/I:H — the attacker recovers the long-term secret key itself, enabling decryption of all past and future traffic under that key. This alone warrants an upward correction of +2 to +3 points from the vendor baseline.
  • Public PoC with demonstrated key recovery: @007bsd's repository provides turnkey end-to-end key recovery code that works on shipped wolfSSL binaries. Recovery of 98.5% of secret coefficients with ~600 chosen ciphertexts is practical and repeatable. This is not a theoretical distinguishing attack — it is a complete cryptographic break of IND-CCA2 security.
  • Narrow but non-trivial exposure surface: ML-KEM adoption is early (<5% of wolfSSL deployments), ARM64 NEON narrows further, and the static-key prerequisite eliminates ephemeral TLS 1.3. Each prerequisite compounds: the realistic exposed population is well under 1% of wolfSSL's installed base. This prevents CRITICAL but does not reach LOW.
  • Embedded/IoT patch lag extends exposure window: wolfSSL is embedded in firmware across IoT, automotive, and industrial devices where update cycles are measured in quarters or years. Devices that adopted ML-KEM early (CNSA 2.0 pilots, government/defense IoT) may remain vulnerable for extended periods.
  • Role multiplier: wolfSSL is deployed across low-value roles (consumer IoT, dev boards) through high-value roles (automotive ECUs, industrial control gateways, government/military embedded systems, TPM-backed key stores). For high-value roles: (1) Government/defense embedded systems adopting ML-KEM under CNSA 2.0 mandates are the most plausible static-key deployments on ARM64 — the chain succeeds here and the blast radius is *key compromise → decryption of classified communications → national security impact*. (2) Industrial/OT gateways using wolfSSL with pinned ML-KEM keys face *device impersonation and traffic decryption*. These roles represent ≥1% of wolfSSL's installed base (wolfSSL explicitly markets to government, automotive, and industrial sectors), establishing a HIGH floor per the deployment-role rule. The chain requires ML-KEM enablement, which is currently rare but growing in exactly these high-value sectors.

Why not higher?

CRITICAL would require either broader exposure or confirmed in-the-wild exploitation. ML-KEM adoption remains early — the vast majority of wolfSSL deployments still use classical X25519/ECDH and are completely unaffected. The static-key prerequisite eliminates the most common use case (ephemeral TLS 1.3 hybrid handshakes). The 10⁵–10⁶ query budget, while feasible, provides a detection window that ephemeral-key deployments never reach. Without evidence that ≥10% of wolfSSL's installed base is running ML-KEM with static keys on ARM64 NEON, the CRITICAL floor is not met.

Why not lower?

MEDIUM would understate the catastrophic impact for affected deployments. This is a full private-key recovery with a public PoC — the most severe class of cryptographic break short of algorithm compromise. wolfSSL is a FIPS-validated library explicitly marketed for government, military, automotive, and industrial use cases where static ML-KEM keys are the most likely deployment pattern. The deployment-role floor (HIGH) applies because these high-value roles represent ≥1% of wolfSSL's installed base and the chain succeeds in them with fleet/national-security-scale impact. EPSS and current exploitation status reflect population-level probability, not impact — they should not override the floor.

06 · Verification

Crowdsourced verification payload.

Run this script on each target host (or against firmware images) where wolfSSL may be installed. Execute as any user with read access to the filesystem: bash check_cve_2026_6330.sh. The script checks for wolfSSL library presence, version, ARM64 NEON enablement, and ML-KEM configuration.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# CVE-2026-6330 Detection Script
# Checks for vulnerable wolfSSL ML-KEM NEON codepath
# Output: VULNERABLE / PATCHED / UNKNOWN
# Exit codes: 2=VULNERABLE, 0=PATCHED, 1=UNKNOWN

set -euo pipefail

RESULT="UNKNOWN"
ARCH=$(uname -m 2>/dev/null || echo "unknown")

# Locate wolfSSL library
WOLFSSL_LIB=""
for candidate in \
  /usr/lib/libwolfssl.so \
  /usr/local/lib/libwolfssl.so \
  /usr/lib/aarch64-linux-gnu/libwolfssl.so \
  /usr/lib64/libwolfssl.so \
  /opt/wolfssl/lib/libwolfssl.so; do
  if [ -f "$candidate" ]; then
    WOLFSSL_LIB="$candidate"
    break
  fi
done

# Also check pkg-config
if [ -z "$WOLFSSL_LIB" ] && command -v pkg-config &>/dev/null; then
  WOLFSSL_LIB=$(pkg-config --variable=libdir wolfssl 2>/dev/null || true)
  if [ -n "$WOLFSSL_LIB" ]; then
    WOLFSSL_LIB="${WOLFSSL_LIB}/libwolfssl.so"
    [ ! -f "$WOLFSSL_LIB" ] && WOLFSSL_LIB=""
  fi
fi

if [ -z "$WOLFSSL_LIB" ]; then
  echo "[INFO] wolfSSL library not found on this host."
  echo "UNKNOWN"
  exit 1
fi

echo "[INFO] Found wolfSSL at: $WOLFSSL_LIB"

# Extract version string from library
VERSION=$(strings "$WOLFSSL_LIB" 2>/dev/null | grep -oP 'wolfSSL \K[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true)

if [ -z "$VERSION" ]; then
  # Try wolfssl-config
  if command -v wolfssl-config &>/dev/null; then
    VERSION=$(wolfssl-config --version 2>/dev/null || true)
  fi
fi

if [ -z "$VERSION" ]; then
  echo "[WARN] Could not determine wolfSSL version."
  echo "UNKNOWN"
  exit 1
fi

echo "[INFO] wolfSSL version: $VERSION"
echo "[INFO] Architecture: $ARCH"

# Parse version components
IFS='.' read -r MAJOR MINOR PATCH <<< "$VERSION"

# Check if ARM64/aarch64
IS_ARM64=false
if [[ "$ARCH" == "aarch64" || "$ARCH" == "arm64" ]]; then
  IS_ARM64=true
fi

# Check NEON symbols in library
HAS_NEON=false
if $IS_ARM64 && strings "$WOLFSSL_LIB" 2>/dev/null | grep -qi 'neon\|mlkem.*neon\|kyber.*neon'; then
  HAS_NEON=true
fi

# Version comparison: vulnerable is 5.7.4 <= version <= 5.9.1
is_vulnerable_version() {
  if [ "$MAJOR" -lt 5 ]; then return 1; fi
  if [ "$MAJOR" -gt 5 ]; then return 1; fi
  # MAJOR is 5
  if [ "$MINOR" -lt 7 ]; then return 1; fi
  if [ "$MINOR" -eq 7 ] && [ "$PATCH" -lt 4 ]; then return 1; fi
  if [ "$MINOR" -gt 9 ]; then return 1; fi
  if [ "$MINOR" -eq 9 ] && [ "$PATCH" -ge 2 ]; then return 1; fi
  return 0
}

if is_vulnerable_version; then
  if $IS_ARM64; then
    echo "[ALERT] wolfSSL $VERSION on ARM64 — NEON ML-KEM codepath is vulnerable to CVE-2026-6330."
    RESULT="VULNERABLE"
  else
    echo "[INFO] wolfSSL $VERSION is in the vulnerable range but this host is $ARCH (not ARM64)."
    echo "[INFO] CVE-2026-6330 (NEON) does not apply. Check CVE-2026-10097 (AVX2) if x86_64."
    RESULT="PATCHED"
  fi
else
  echo "[INFO] wolfSSL $VERSION is outside the vulnerable range (5.7.4–5.9.1)."
  RESULT="PATCHED"
fi

echo "$RESULT"
case "$RESULT" in
  VULNERABLE) exit 2 ;;
  PATCHED)    exit 0 ;;
  *)          exit 1 ;;
esac