Skip to content

VNX-JAVA-018: Java RSA cipher without OAEP padding

Detects javax.crypto.Cipher instances created for RSA with PKCS#1 v1.5 padding or no padding (including the bare "RSA" transformation, which defaults to PKCS1Padding), inline or through a constant, which are vulnerable to Bleichenbacher-style padding oracle attacks. Use RSA/ECB/OAEPWithSHA-256AndMGF1Padding instead.

Updated 02 Nov 2026Checked against cli@de9b52a
Field Value
Rule ID VNX-JAVA-018
Severity High
SARIF level error
Kind sast
Languages Java
CWE CWE-780
CAPEC CAPEC-463
ATT&CK T1600
CWSS vector CWSS:1.0/TI:H/AP:RU/AL:S/IC:N/FC:LT/RP:RU/RL:S/AV:L/AS:N/IN:A/SC:A/BI:H/DI:H/EX:H/EC:N/P:H
Tags crypto rsa padding java
Source internal/sast/rules/vnx-java-018.rego

Overview

This rule flags calls to Cipher.getInstance() whose transformation is RSA/<mode>/PKCS1Padding, RSA/<mode>/NoPadding or the bare "RSA" (which the SunJCE provider resolves to RSA/ECB/PKCS1Padding), written inline or through a String constant in the same file. These padding schemes are cryptographically weak and expose applications to a class of attack known as the Bleichenbacher padding oracle attack (also called the “million message attack”). The vulnerability is tracked as CWE-780 (Use of RSA Algorithm without OAEP).

PKCS#1 v1.5 padding prepends a structured sequence of bytes to the plaintext before encryption. The structure is deterministic enough that a server decrypting a modified ciphertext and responding differently based on whether the padding is valid leaks a single bit of information per query. Bleichenbacher showed in 1998 that an attacker who can distinguish “valid padding” from “invalid padding”, even through indirect means such as differing error messages, timing variations, or TLS alert types, can decrypt any RSA ciphertext with approximately one million adaptive chosen-ciphertext queries. Despite being over two decades old, this attack remains practical and has been rediscovered repeatedly in TLS implementations (ROBOT attack, 2017).

OAEP (Optimal Asymmetric Encryption Padding) provides probabilistic encryption and is provably secure in the random oracle model. It does not have a padding oracle vulnerability.

Why This Matters

The ROBOT (Return Of Bleichenbacher’s Oracle Threat) vulnerability, disclosed in 2017, demonstrated that 27 of the top 100 Alexa websites, including Facebook, PayPal, and major US government sites, were vulnerable to the 1998 Bleichenbacher attack. An attacker with the ability to make adaptive queries against the TLS handshake could decrypt TLS session keys encrypted under RSA PKCS#1 v1.5, breaking the confidentiality of past and present sessions.

In application code, the risk is equally concrete. An API that uses RSA PKCS#1 v1.5 to decrypt tokens, license keys, or session data, and that returns different HTTP status codes or error messages depending on whether decryption succeeded, provides the oracle an attacker needs. The attacker doesn’t need to access your private key directly, they use your own server as a decryption oracle to recover the plaintext incrementally.

No-padding mode (NoPadding) is even more dangerous: it provides textbook RSA with no randomness, making it trivially malleable. Multiplying a ciphertext by the encryption of a known value produces a ciphertext that decrypts to the plaintext multiplied by the known value, a property that enables chosen-ciphertext attacks without any oracle at all.

What Gets Flagged

// FLAGGED: PKCS#1 v1.5 padding is vulnerable to padding oracle attacks
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] plaintext = cipher.doFinal(ciphertext);

// FLAGGED: no padding is textbook RSA, fully malleable
Cipher cipher = Cipher.getInstance("RSA/NONE/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);

// FLAGGED: bare "RSA" resolves to RSA/ECB/PKCS1Padding in SunJCE
Cipher cipher = Cipher.getInstance("RSA");

// NOT FLAGGED: OAEP, and RSA signatures/key generation
Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
Signature.getInstance("SHA256withRSA");

Remediation

  1. Replace PKCS1Padding and NoPadding with OAEPWithSHA-256AndMGF1Padding in all Cipher.getInstance() calls that use RSA.
  2. For new code, prefer OAEPWithSHA-512AndMGF1Padding if your key size is 4096 bits or larger.
  3. Do not catch BadPaddingException and IllegalBlockSizeException separately and return different responses, always treat any decryption failure identically to prevent timing or error-message oracles.
  4. Consider migrating bulk encryption to hybrid encryption: use RSA-OAEP to encrypt only an ephemeral AES key, then use AES-GCM for the actual data.
// SAFE: OAEP padding prevents padding oracle attacks
import javax.crypto.Cipher;
import javax.crypto.spec.OAEPParameterSpec;
import javax.crypto.spec.PSource;
import java.security.spec.MGF1ParameterSpec;

OAEPParameterSpec oaepSpec = new OAEPParameterSpec(
    "SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT
);

Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey, oaepSpec);

byte[] plaintext;
try {
    plaintext = cipher.doFinal(ciphertext);
} catch (Exception e) {
    // Always return the same error regardless of failure reason
    throw new CryptoException("Decryption failed");
}

References

Suppressing this rule

Put a nosec comment on the line, or on line 1 to cover the whole file. Use the comment marker of the file’s language (#, //, -- or ;):

# nosec vnx-java-018
// nosec vnx-java-018

Or record an ignore rule: vulnetix ignore add --rule vnx-java-018 --reason "...". See Suppressing findings.

Edit this pageSources: cli/internal/sast/rules/vnx-java-018.rego, cli/internal/sast/docs/vnx-java-018.md
esc
↑ ↓ move↵ openSearches in your browser. A key like autonomy.max or a code like threshold_required jumps straight to it.