GHSA-2gqc-6j2q-83qp

Suggest an improvement
Source
https://github.com/advisories/GHSA-2gqc-6j2q-83qp
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/01/GHSA-2gqc-6j2q-83qp/GHSA-2gqc-6j2q-83qp.json
JSON Data
https://api.osv.dev/v1/vulns/GHSA-2gqc-6j2q-83qp
Aliases
Downstream
CGA (2)
Published
2026-01-15T18:17:15Z
Modified
2026-09-10T03:50:32Z
Severity
  • 8.9 (High) CVSS_V4 - CVSS:4.0/AV:N/AC:H/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:H/SI:N/SA:N CVSS Calculator
Summary
RustCrypto Utilities cmov: `thumbv6m-none-eabi` compiler emits non-constant time assembly when using `cmovnz`
Details

Summary

thumbv6m-none-eabi (Cortex M0, M0+ and M1) compiler emits non-constant time assembly when using cmovnz (portable version). I did not found any other target with the same behaviour but I did not go through all targets supported by Rust.

Details

It seems that, during mask computation, an LLVM optimisation pass is detecting that bitnz is returning 0 or 1, that can be interpreted as a boolean. This intermediate value is not masked by a call to black_box and thus the subsequent .wrapping_sub(1) can be interpreted as a conditional bitwise conditional not.

PoC

This is an attempt at having a minimal faulty code. In a library crate with an up-to-date cmov as only dependency, the content of src/lib.rs is:

#![no_std]
use cmov::Cmov;

#[inline(never)]
pub fn test_ct_cmov(a: &mut u8, b: u8, c: u8) {
    a.cmovnz(&b, c);
}

The resulting assembly emitted (shown using cargo asm --release --target thumbv6m-none-eabi that uses cargo-show-asm):

Collapsed assembly
.section .text.not_ct::test_ct_cmov,"ax",%progbits
	.globl	not_ct::test_ct_cmov
	.p2align	1
	.type	not_ct::test_ct_cmov,%function
	.code	16
	.thumb_func
not_ct::test_ct_cmov:
	.fnstart
	.cfi_sections .debug_frame
	.cfi_startproc
	.save	{r7, lr}
	push {r7, lr}
	.cfi_def_cfa_offset 8
	.cfi_offset lr, -4
	.cfi_offset r7, -8
	.setfp	r7, sp
	add r7, sp, #0
	.cfi_def_cfa_register r7
	.pad	#8
	sub sp, #8
	movs r3, #0
	lsls r2, r2, #24
	bne .LBB0_2
	mvns r3, r3
.LBB0_2:
	ldrb r2, [r0]
	str r3, [sp, #4]
	str r3, [sp]
	mov r3, sp
	@APP
	@NO_APP
	ldr r3, [sp]
	bics r1, r3
	ands r2, r3
	adds r1, r2, r1
	strb r1, [r0]
	add sp, #8
	pop {r7, pc}

The non-constant time assembly is:

    bne  .LBB0_2
    mvns r3, r3
.LBB0_2:

Impact

The exact impact is unclear, especially since cmov clearly warns users that the portable version is best-effort.

Database specific
{
    "cwe_ids":  [
        "CWE-203",
        "CWE-208"
    ],
    "github_reviewed":  true,
    "github_reviewed_at":  "2026-01-15T18:17:15Z",
    "nvd_published_at":  "2026-01-15T20:16:05Z",
    "severity":  "HIGH"
}
References

Affected packages

crates.io / cmov

Package

Affected ranges

Type
SEMVER
Events
Introduced
0 Unknown introduced version / All previous versions are affected
Fixed
0.4.4

Database specific

source
"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/01/GHSA-2gqc-6j2q-83qp/GHSA-2gqc-6j2q-83qp.json"