CVE-2026-31790 is a return-value check bug in OpenSSL's RSASVE key encapsulation path. When RSA_public_encrypt fails — typically because the public key is malformed or internally inconsistent — it returns a negative value. The code checks != 0 instead of > 0, treating that failure as success. The output buffer then contains uninitialized stack memory, which gets transmitted as valid ciphertext. The CVSS 7.5 reflects the severity of that leak: any system using EVP_PKEY_encapsulate() with RSA keys can inadvertently disclose stack contents to attackers who control or supply the public key.
This affects any application encapsulating against external input: TLS servers receiving client key shares, any hybrid encryption scheme accepting untrusted public keys, any system doing RSA-KEM or RSA-OAEP encapsulation with data from the network. The high-level EVP_PKEY_encapsulate() API is supposed to abstract away RSA layer details — that's the entire point of using it. But it inherits the bug from the underlying RSA_public_encrypt wrapper, and it doesn't sanitize the error path.
The immediate workaround is to call EVP_PKEY_public_check() on the RSA key before calling EVP_PKEY_encapsulate(). This catches malformed keys at the EVP layer before they reach the flawed RSA_public_encrypt path. However, this is a burden that should belong to the library, not the caller. If you're using the documented high-level API correctly, you shouldn't need to understand return-value semantics three layers down to avoid memory disclosure.
This isn't an isolated error. OpenSSL has a documented history of the same mistake in similar contexts — RSA blinding (CVE-2003-0131), DH error-path mishandling (CVE-2016-0701), RSASVE flaws (CVE-2017-15361/ROCA). The pattern clusters around RSA encapsulation and key establishment, where functions with negative-on-error semantics get confused with functions returning 1 on success. This is institutional, not accidental — the same class of flaw keeps appearing in the same code family.
One additional detail to verify in the patch: check whether the fix includes explicit zeroing of the output buffer on error returns, not just the return-value correction. If the output buffer isn't zeroed on the error path, other error conditions (future bugs, allocation failures) could still leak uninitialized memory through the same interface. Review the commit to confirm the fix is complete, not just correct.