CVE-2026-47842 Migration Guide
Migrating off the deprecated AesBytesEncryptor in NES for Spring Security, including which changes require re-encrypting stored data.
CVE-2026-47842 Migration Guide
Remediating this CVE requires migration, in addition to a version update. The patch for this CVE deprecates AesBytesEncryptor and adds two replacements: AesCbcBytesEncryptor and AesGcmBytesEncryptor. However, the original AesBytesEncryptor has the original behavior because it is the only class that can read data already encrypted with it. Upgrading to a patched release does not by itself remediate an affected application: the application must move to one of the new encryptors, and in most cases re-encrypt its stored data.
The old class was not simply fixed because it cannot be made safe without changing how it stores data, and that change would make everything already encrypted with it unreadable. The patch therefore leaves it as it is and adds the new classes alongside it.
Applies To
Every NES for Spring Security line (4.2.x, 5.5.x, 5.7.x, 5.8.x, 6.2.x, 6.3.x, 6.4.x and 6.5.x) ships AesBytesEncryptor, and every line carries AesCbcBytesEncryptor and AesGcmBytesEncryptor as of its CVE-2026-47842 patch release. The replacement API shown below is identical in all eight versions; what the existing code can look like differs on 4.2.x, noted where it matters.
Identifying Affected Code
Every use of the old API raises two separate questions, and they have different answers:
- Is the stored ciphertext exposed to the CVE?
- Does migrating to a replacement require re-encrypting it?
| Usage | Exposed | Re-encryption to migrate |
|---|---|---|
new AesBytesEncryptor(password, salt) | Yes — the two-argument constructor passes a null IV generator | Yes |
new AesBytesEncryptor(secretKey, null, CipherAlgorithm.CBC) | Yes | Yes — no IV is stored with the ciphertext |
Encryptors.queryableText(password, salt) | Yes — deterministic by design, see below | Yes, and there is no replacement |
new AesBytesEncryptor(password, salt, ivGenerator, …) with a non-null IV generator, or CipherAlgorithm.GCM | No | Yes — password-derived, and the key derivation changed |
Encryptors.standard(), stronger(), text(), delux() | No — every call uses a fresh random IV | Yes — password-derived, and the key derivation changed |
new AesBytesEncryptor(secretKey, ivGenerator, CipherAlgorithm.CBC) | No | No — AesCbcBytesEncryptor.withSecretKey(secretKey).ivGenerator(ivGenerator) reads it unchanged |
new AesBytesEncryptor(secretKey, …, CipherAlgorithm.GCM) | No | No — AesGcmBytesEncryptor.withSecretKey(secretKey) reads it unchanged |
Only AES/CBC with a null IV generator is exposed. The four Encryptors factory methods never were, though the same patch deprecates them. Because those methods derive their key from a password, the replacement cannot read what they wrote, so migrating off them requires re-encryption — like any other such migration.
The secretKey rows apply from 5.5.x up; the SecretKey constructor arrived in Spring Security 5.4. On 4.2.x AesBytesEncryptor is not public at all (it became public in 5.2), so new AesBytesEncryptor(...) cannot appear in application code on that line — Encryptors.queryableText is the only affected usage there.
Encryptors.queryableText
Encryptors.queryableText(password, salt) is present on the 4.2.x, 5.5.x, 5.7.x and 5.8.x lines and delegates straight to the affected constructor.
If your are leveraging this method in your codebase, note that there is no secure replacement. The method was removed rather than replaced, because deterministic encryption cannot be made resistant to the correlation the CVE describes. If you depend on querying encrypted columns, one option is to perform that check at the datastore level rather than reproducing it in application code.
Migrating Stored Data
Moving from a password-derived encryptor to either replacement is a data migration: ciphertext written by the old encryptor cannot be read by the new one, so every stored value has to be decrypted with the old encryptor and written back with the new. It may be necessary to keep the old encryptor wired up as the reader until all all data has migrated.
Both replacements are built through a builder, for example AesGcmBytesEncryptor.withPassword(password, salt).build(). A migration is also the natural point to rotate the password: the old encryptor is constructed with the old password to read, the replacement with the new one to write.
On 4.2.x the old encryptor is the TextEncryptor from Encryptors.queryableText(password, salt), and because that line has no SecretKey constructor, every 4.2.x migration is of this kind.
Verify the result with a round trip on real data, not by the absence of an exception. Pointing AesCbcBytesEncryptor.withSecretKey(key) at ciphertext written under a null IV generator does not fail: the replacement reads the first 16 bytes as the IV and returns the plaintext with those bytes missing.
Replacing Encryptors.text and Encryptors.delux
Encryptors.text and Encryptors.delux return a TextEncryptor: they take a String and return hex-encoded String, which is what makes them convenient for database columns. Both replacements implement BytesEncryptor only, and the hex-encoding TextEncryptor behind the old factory methods is package-private, so there is no public TextEncryptor to migrate to.
Wrap one of the new encryptors instead:
public final class VaultTextEncryptor implements TextEncryptor {
private final BytesEncryptor encryptor;
public VaultTextEncryptor(BytesEncryptor encryptor) {
this.encryptor = encryptor;
}
@Override
public String encrypt(String text) {
return new String(Hex.encode(this.encryptor.encrypt(Utf8.encode(text))));
}
@Override
public String decrypt(String encryptedText) {
return Utf8.decode(this.encryptor.decrypt(Hex.decode(encryptedText)));
}
}
Hex and Utf8 are public members of org.springframework.security.crypto.codec on every NES line. This wrapper restores the TextEncryptor API, not the stored format — values written by Encryptors.text or Encryptors.delux are still password-derived and still need the data migration above.
Additional Information
You can read more about the CVE and its implications in the CVE-2026-47842 vulnerability entry.
- Spring Security reference, Cryptography: Encryptors