Vulnerability Overview (At a Glance)
| Field | Details |
|---|---|
| CVE ID | CVE-2026-23519 |
| Affected Component | RustCrypto cmov crate (portable cmovnz implementation) |
| Affected Versions | cmov < 0.4.4 |
| Fixed Version | cmov 0.4.4 |
| CVSS Score | 8.9 (High) |
| Severity | High |
| Vulnerability Type | Cryptographic Side-Channel (Timing) |
| Exploitability | Difficult but feasible in controlled environments |
| Exploit Availability | Proof-of-concept available (educational/research use only) |
| Attack Vector | Timing observation during cryptographic operations |
| Impact | Potential leakage of secret-dependent values |
| Primary Risk | Loss of confidentiality |
| Platforms Impacted | ARM Cortex-M (thumbv6m-none-eabi: M0/M0+/M1) |
What This Vulnerability Really Is
This vulnerability is not a memory corruption bug, not a crash, and not remotely exploitable in the traditional sense.
It is a cryptographic side-channel flaw.
The RustCrypto cmov crate is designed to provide constant-time conditional move operations. These operations are critical in cryptography because they avoid branches that depend on secret values.
However, on very small ARM embedded CPUs (specifically thumbv6m-none-eabi targets), the portable fallback implementation of cmovnz is compiled by the Rust compiler/LLVM in a way that introduces conditional branching.
Once branching appears, execution time becomes dependent on secret data.
That breaks the core promise of constant-time execution.
Why This Happened
- The
cmovcrate has:- Assembly-based constant-time implementations for many architectures
- A portable Rust fallback for platforms without inline assembly support
- On
thumbv6m-none-eabi, the portable fallback is used. - The fallback uses bit-manipulation logic that should remain branchless.
- LLVM optimizes part of that logic into:
- Boolean evaluation
- Followed by a conditional branch (
bne,beq)
- That branch depends on data derived from secret input.
- Result: timing differences that correlate with secret values
This is not a coding mistake in Rust itself, but a compiler optimization side effect that invalidated constant-time assumptions.
Security Impact
If cryptographic code relies on this cmovnz operation:
- Signature verification
- Key comparison
- MAC verification
- Password / secret checks
An attacker who can:
- Repeatedly trigger the operation
- Measure execution time with sufficient precision
may be able to infer bits of secret data over many measurements.
This is especially relevant for:
- Embedded devices
- IoT firmware
- Hardware wallets
- Secure microcontrollers
- Smart cards or secure boot chains
Exploitation Details (Educational)
Is exploitation easy?
No. This is not a script-kiddie bug.
What an attacker needs:
- Ability to invoke the vulnerable operation repeatedly
- High-resolution timing measurements
- Stable execution environment
- Many samples (thousands to millions)
What can be leaked:
- Bits or patterns derived from secret values
- Not full secrets instantly, but incremental leakage
Why it still matters:
- Side-channel attacks are cumulative
- Embedded devices often run for years
- Attackers with physical or co-located access can exploit this
Proof-of-Concept (PoC)
A minimal proof-of-concept exists that demonstrates:
- The compiled assembly for
thumbv6m-none-eabi - Presence of conditional branch instructions inside
cmovnz - Observable execution differences
The PoC is educational and verification-focused, not weaponized.
It proves:
- The operation is not constant time
- The vulnerability is real and measurable
How to Detect If You Are Affected
1. Dependency Inspection
Check whether your project (or its dependencies) uses:
cmovcrate- Version lower than 0.4.4
This applies to:
- Direct dependencies
- Transitive dependencies
2. Target Inspection
You are at risk only if all of the following are true:
- Target architecture is
thumbv6m-none-eabi - Portable
cmovfallback is used - Code handles secret data
- Timing can be measured
3. Assembly Inspection
Build your project and inspect generated assembly:
- Look for
bne,beq, or similar branches - Inside functions originating from
cmovportable code
If branching is present → not constant time
4. Runtime Timing Test
Create a test loop that:
- Calls
cmovnzrepeatedly - Varies secret inputs
- Measures cycle counts
If timing correlates with input → vulnerable build
Detection Data Sources
| Source | Value |
|---|---|
| CI build logs | Dependency version checks |
| Cargo.lock | Definitive version resolution |
| SBOM (CycloneDX/SPDX) | Long-term inventory |
| Firmware binaries | Assembly inspection |
| Lab timing logs | Side-channel validation |
MITRE Mapping
- CWE-208 – Observable Timing Discrepancy
- CWE-385 – Covert Timing Channel
This vulnerability directly maps to confidentiality loss via side-channel observation.
What This Vulnerability Does Not Do
- Does not crash systems
- Does not allow code execution
- Does not bypass authentication directly
- Does not show obvious logs or alerts
This is a silent weakness, not an active exploit signal.
Official Fix
Upgrade to cmov version 0.4.4 or later
Official advisory and patch (includes fix details and commit):
👉 https://github.com/RustCrypto/utils/security/advisories/GHSA-2gqc-6j2q-83qp
Recommended Mitigation Steps
- Upgrade
cmovto ≥ 0.4.4 - Rebuild all affected firmware or binaries
- Redeploy embedded images
- Add CI enforcement
- Track dependencies via SBOM
- Avoid assuming “portable” means “constant-time”
CI Protection: GitHub Actions Bash Script
Below is a drop-in bash script that fails builds if a vulnerable cmov version is detected.
CI Script (Bash)
#!/usr/bin/env bash
set -euo pipefail
echo "[*] Checking for vulnerable cmov versions..."
if ! command -v cargo >/dev/null 2>&1; then
echo "[!] Cargo not found. Skipping cmov check."
exit 0
fi
VULN_FOUND=0
cargo tree -e normal | while read -r line; do
if echo "$line" | grep -E "cmov v0\.[0-3]\." >/dev/null; then
echo "[!] Vulnerable cmov detected: $line"
VULN_FOUND=1
fi
done
if [ "$VULN_FOUND" -eq 1 ]; then
echo "[X] Build blocked: cmov version < 0.4.4 is present."
exit 1
else
echo "[✓] No vulnerable cmov versions detected."
fi
How to Use
- Place this script in your repository (e.g.,
ci/check_cmov.sh) - Call it from GitHub Actions before build or release
- Ensures vulnerable firmware is never shipped
Final Takeaway
This vulnerability is subtle but serious.
It does not break systems loudly, but it weakens cryptographic guarantees silently, which is often worse in embedded and security-critical environments.
If you build cryptographic software for Cortex-M devices and rely on RustCrypto utilities:
Upgrading is mandatory, not optional.
