Improper random reading in CIRCL
Description
When sampling randomness for a shared secret, the implementation of Kyber and FrodoKEM, did not check whether crypto/rand.Read() returns an error. In rare deployment cases (error thrown by the Read() function), this could lead to a predictable shared secret.
The tkn20 and blindrsa components did not check whether enough randomness was returned from the user provided randomness source. Typically the user provides crypto/rand.Reader, which in the vast majority of cases will always return the right number random bytes. In the cases where it does not, or the user provides a source that does not, the blinding for blindrsa is weak and integrity of the plaintext is not ensured in tkn20.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Missing error checks on randomness reading in CIRCL's Kyber, FrodoKEM, tkn20, and blindrsa could lead to predictable secrets or weakened security.
The vulnerability lies in the CIRCL cryptographic library, where the implementation of Kyber and FrodoKEM key encapsulation mechanisms (KEMs) did not check the error return from crypto/rand.Read() when sampling randomness for a shared secret [1]. Similarly, the tkn20 and blindrsa components failed to verify that the provided randomness source returned enough bytes [1]. In typical deployments, crypto/rand.Reader almost always succeeds, so the bug manifests only in rare error conditions or when a user-supplied source is insufficient.
Exploitation requires a scenario where crypto/rand.Read() returns an error (e.g., system resource exhaustion) or the user provides a randomness source that returns fewer bytes than expected [1]. An attacker would need to be in a position to observe or trigger such failures, but no authentication is required if the library is used in a context where the attacker can influence the environment.
If exploited, the shared secret generated by Kyber or FrodoKEM becomes predictable, breaking the confidentiality guarantees of the KEM [1]. For blindrsa, weak randomness weakens the blinding mechanism, potentially leaking signer or message information. For tkn20, insufficient randomness compromises plaintext integrity [1].
Cloudflare patched the issue in CIRCL v1.3.3 [3], adding proper error checking. The fix includes using io.ReadFull for blindrsa and tkn20, and panicking on read error for Kyber encapsulation seed [4]. Users should update to v1.3.3 or later to mitigate the risk.
AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
github.com/cloudflare/circlGo | < 1.3.3 | 1.3.3 |
Affected products
29- osv-coords28 versionspkg:apk/chainguard/aactlpkg:apk/chainguard/flux-0pkg:apk/chainguard/flux-compatpkg:apk/chainguard/kyverno-1.8pkg:apk/chainguard/kyverno-cli-1.8pkg:apk/chainguard/kyverno-init-container-1.8pkg:apk/chainguard/pulumi-language-javapkg:apk/chainguard/tekton-pipelinespkg:apk/chainguard/tekton-pipelines-entrypointpkg:apk/chainguard/tekton-pipelines-eventspkg:apk/chainguard/tekton-pipelines-noppkg:apk/chainguard/tekton-pipelines-resolverspkg:apk/chainguard/tekton-pipelines-sidecarlogresultspkg:apk/chainguard/tekton-pipelines-webhookpkg:apk/chainguard/tekton-pipelines-workingdirinitpkg:apk/wolfi/aactlpkg:apk/wolfi/flux-compatpkg:apk/wolfi/pulumi-language-javapkg:apk/wolfi/tekton-pipelinespkg:apk/wolfi/tekton-pipelines-entrypointpkg:apk/wolfi/tekton-pipelines-eventspkg:apk/wolfi/tekton-pipelines-noppkg:apk/wolfi/tekton-pipelines-resolverspkg:apk/wolfi/tekton-pipelines-sidecarlogresultspkg:apk/wolfi/tekton-pipelines-webhookpkg:apk/wolfi/tekton-pipelines-workingdirinitpkg:golang/github.com/cloudflare/circlpkg:rpm/opensuse/velociraptor&distro=openSUSE%20Tumbleweed
< 0.4.12-r7+ 27 more
- (no CPE)range: < 0.4.12-r7
- (no CPE)range: < 0
- (no CPE)range: < 0
- (no CPE)range: < 1.8.5-r2
- (no CPE)range: < 1.8.5-r2
- (no CPE)range: < 1.8.5-r2
- (no CPE)range: < 0.9.3-r2
- (no CPE)range: < 0
- (no CPE)range: < 0
- (no CPE)range: < 0
- (no CPE)range: < 0
- (no CPE)range: < 0
- (no CPE)range: < 0
- (no CPE)range: < 0
- (no CPE)range: < 0
- (no CPE)range: < 0.4.12-r7
- (no CPE)range: < 0
- (no CPE)range: < 0.9.3-r2
- (no CPE)range: < 0
- (no CPE)range: < 0
- (no CPE)range: < 0
- (no CPE)range: < 0
- (no CPE)range: < 0
- (no CPE)range: < 0
- (no CPE)range: < 0
- (no CPE)range: < 0
- (no CPE)range: < 1.3.3
- (no CPE)range: < 0.7.0.4.git142.862ef23-1.1
- Cloudflare/CIRCLv5Range: 0
Patches
1ff8d91225f89Check for crypto/rand errors and ReadFull io.Readers
11 files changed · +29 −11
abe/cpabe/tkn20/internal/tkn/bk.go+1 −1 modified@@ -78,7 +78,7 @@ func DeriveAttributeKeysCCA(rand io.Reader, sp *SecretParams, attrs *Attributes) func EncryptCCA(rand io.Reader, public *PublicParams, policy *Policy, msg []byte) ([]byte, error) { seed := make([]byte, macKeySeedSize) - _, err := rand.Read(seed) + _, err := io.ReadFull(rand, seed) if err != nil { return nil, err }
blindsign/blindrsa/blindrsa.go+1 −1 modified@@ -183,7 +183,7 @@ func (v RSAVerifier) Blind(random io.Reader, message []byte) ([]byte, blindsign. } salt := make([]byte, v.hash.Size()) - _, err := random.Read(salt) + _, err := io.ReadFull(random, salt) if err != nil { return nil, nil, err }
kem/frodo/frodo640shake/frodo.go+3 −1 modified@@ -160,7 +160,9 @@ func generateKeyPair(rand io.Reader) (*PublicKey, *PrivateKey, error) { func (pk *PublicKey) EncapsulateTo(ct []byte, ss []byte, seed []byte) { if seed == nil { seed = make([]byte, EncapsulationSeedSize) - _, _ = cryptoRand.Read(seed[:]) + if _, err := cryptoRand.Read(seed[:]); err != nil { + panic(err) + } } if len(seed) != EncapsulationSeedSize { panic("seed must be of length EncapsulationSeedSize")
kem/kyber/kyber1024/kyber.go+3 −1 modified@@ -106,7 +106,9 @@ func GenerateKeyPair(rand io.Reader) (*PublicKey, *PrivateKey, error) { func (pk *PublicKey) EncapsulateTo(ct, ss []byte, seed []byte) { if seed == nil { seed = make([]byte, EncapsulationSeedSize) - cryptoRand.Read(seed[:]) + if _, err := cryptoRand.Read(seed[:]); err != nil { + panic(err) + } } else { if len(seed) != EncapsulationSeedSize { panic("seed must be of length EncapsulationSeedSize")
kem/kyber/kyber512/kyber.go+3 −1 modified@@ -106,7 +106,9 @@ func GenerateKeyPair(rand io.Reader) (*PublicKey, *PrivateKey, error) { func (pk *PublicKey) EncapsulateTo(ct, ss []byte, seed []byte) { if seed == nil { seed = make([]byte, EncapsulationSeedSize) - cryptoRand.Read(seed[:]) + if _, err := cryptoRand.Read(seed[:]); err != nil { + panic(err) + } } else { if len(seed) != EncapsulationSeedSize { panic("seed must be of length EncapsulationSeedSize")
kem/kyber/kyber768/kyber.go+3 −1 modified@@ -106,7 +106,9 @@ func GenerateKeyPair(rand io.Reader) (*PublicKey, *PrivateKey, error) { func (pk *PublicKey) EncapsulateTo(ct, ss []byte, seed []byte) { if seed == nil { seed = make([]byte, EncapsulationSeedSize) - cryptoRand.Read(seed[:]) + if _, err := cryptoRand.Read(seed[:]); err != nil { + panic(err) + } } else { if len(seed) != EncapsulationSeedSize { panic("seed must be of length EncapsulationSeedSize")
kem/kyber/templates/pkg.templ.go+3 −1 modified@@ -110,7 +110,9 @@ func GenerateKeyPair(rand io.Reader) (*PublicKey, *PrivateKey, error) { func (pk *PublicKey) EncapsulateTo(ct, ss []byte, seed []byte) { if seed == nil { seed = make([]byte, EncapsulationSeedSize) - cryptoRand.Read(seed[:]) + if _, err := cryptoRand.Read(seed[:]); err != nil { + panic(err) + } } else { if len(seed) != EncapsulationSeedSize { panic("seed must be of length EncapsulationSeedSize")
kem/sike/sikep434/sike.go+3 −1 modified@@ -130,7 +130,9 @@ func (*scheme) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) { func (sch *scheme) Encapsulate(pk kem.PublicKey) (ct []byte, ss []byte, err error) { var seed [EncapsulationSeedSize]byte - cryptoRand.Read(seed[:]) + if _, err := cryptoRand.Read(seed[:]); err != nil { + return nil, nil, err + } return sch.EncapsulateDeterministically(pk, seed[:]) }
kem/sike/sikep503/sike.go+3 −1 modified@@ -130,7 +130,9 @@ func (*scheme) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) { func (sch *scheme) Encapsulate(pk kem.PublicKey) (ct []byte, ss []byte, err error) { var seed [EncapsulationSeedSize]byte - cryptoRand.Read(seed[:]) + if _, err := cryptoRand.Read(seed[:]); err != nil { + return nil, nil, err + } return sch.EncapsulateDeterministically(pk, seed[:]) }
kem/sike/sikep751/sike.go+3 −1 modified@@ -130,7 +130,9 @@ func (*scheme) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) { func (sch *scheme) Encapsulate(pk kem.PublicKey) (ct []byte, ss []byte, err error) { var seed [EncapsulationSeedSize]byte - cryptoRand.Read(seed[:]) + if _, err := cryptoRand.Read(seed[:]); err != nil { + return nil, nil, err + } return sch.EncapsulateDeterministically(pk, seed[:]) }
kem/sike/templates/pkg.templ.go+3 −1 modified@@ -135,7 +135,9 @@ func (*scheme) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) { func (sch *scheme) Encapsulate(pk kem.PublicKey) (ct []byte, ss []byte, err error) { var seed [EncapsulationSeedSize]byte - cryptoRand.Read(seed[:]) + if _, err := cryptoRand.Read(seed[:]); err != nil { + return nil, nil, err + } return sch.EncapsulateDeterministically(pk, seed[:]) }
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/advisories/GHSA-2q89-485c-9j2xghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2023-1732ghsaADVISORY
- github.com/cloudflare/circl/commit/ff8d91225f8954b4970b6d6382d2e4c78f4a4cf8ghsaWEB
- github.com/cloudflare/circl/releases/tag/v1.3.3ghsaWEB
- github.com/cloudflare/circl/security/advisories/GHSA-2q89-485c-9j2xghsaWEB
News mentions
0No linked articles in our index yet.