https://blog.trailofbits.com/2026/02/18/carelessness-versus-craftsmanship-in-cryptography/
reports:
Two popular AES libraries, aes-js and pyaes, “helpfully” provide a default IV
in their AES-CTR API, leading to a large number of key/IV reuse bugs. These
bugs potentially affect thousands of downstream projects.
[...]
Reusing a key/IV pair leads to serious security issues: if you encrypt two
messages in CTR mode or GCM with the same key and IV, then anybody with access
to the ciphertexts can recover the XOR of the plaintexts, and that’s a very
bad thing.
[...]
As you might guess from the names, aes-js and pyaes are JavaScript and Python
libraries that implement the AES block cipher. They’re pretty widely used: the
Node.js package manager (npm) repository lists 850 aes-js dependents as of this
writing, and GitHub estimates that over 700,000 repositories integrate aes-js
and nearly 23,000 repositories integrate pyaes, either as direct or indirect
dependencies.
[...]
The default IV problem
----------------------
We’ll start with the biggest concern Trail of Bits identified: when
instantiating AES in CTR mode, aes-js and pyaes do not require an IV.
Instead, if no IV is specified, libraries will supply a default IV of
0x00000000_00000000_00000000_00000001.
Worse still, the documentation provides examples of this behavior as
typical behavior. For example, this comes from the pyaes README:
aes = pyaes.AESModeOfOperationCTR(key)
plaintext = "Text may be any length you wish, no padding is required"
ciphertext = aes.encrypt(plaintext)
The first line ought to be something like
aes = pyaes.AESModeOfOperationCTR(key, iv),
where iv is a randomly generated value. Users who follow this example will
always wind up with the same IV, making it inevitable that many (if not most)
will wind up with a key/IV reuse bug in their software. Most people are looking
for an easy-to-use encryption library, and what’s simpler than just passing in
the key?
That apparent simplicity has led to widespread use of the “default,” creating
a multitude of key/IV reuse vulnerabilities.
Other issues
============
Lack of modern cipher modes
---------------------------
aes-js and pyaes don’t support modern cipher modes like AES-GCM and
AES-GCM-SIV. In most contexts where you want to use AES, you likely want to
use these modes, as they offer authentication in addition to encryption.
This is no small issue: even for programs that use aes-js or pyaes with
distinct key/IV pairs, AES CTR ciphertexts are still malleable: if an
attacker changes the bits in the ciphertext, then the resulting bits in the
plaintext will change in exactly the same way, and CTR mode doesn’t provide
any way to detect this. This can allow an attacker to recover an ECDSA key
by tricking the user into signing messages with a series of related keys.
Cipher modes like GCM and GCM-SIV prevent this by computing keyed “tags”
that will fail to authenticate when the ciphertext is modified, even by a
single bit. Pretty nifty feature, but support is completely absent from
aes-js and pyaes.
Timing problems
---------------
On top of that, both aes-js and pyaes are vulnerable to side-channel attacks.
Both libraries use lookup tables for the AES S-box, which enables cache-timing
attacks. On top of that, there are timing issues in the PKCS7 implementation,
enabling a padding oracle attack when used in CBC mode.
Lack of updates
---------------
aes-js hasn’t been updated since 2018. pyaes hasn’t been touched since 2017.
Since then, a number of issues have been filed against both libraries.
Here are just a few examples:
- Outdated distribution tools for pyaes (it relies on distutils,
which has been deprecated since October 2023)
- Performance issues in the streaming API
- UTF-8 encoding problems in aes-js
- Lack of IV and key generation routines in both
Developer response
------------------
Finally, in 2022, an issue was filed against aes-js about the default IV
problem. The developer’s response ended with the following:
The AES block cipher is a cryptographic primitive, so it’s very important
to understand and use it properly, based on its application. It’s a
powerful tool, and with great power, yadda, yadda, yadda. :)
[...]
In November 2025, we reached out to the maintainer via email and via X, but we
received no response.
[...]
We identified several pieces of software impacted by the default IV behavior
in pyaes and aes-js. Many of the programs we found have been deprecated, and
we even found a couple of vulnerable wallets for cryptocurrencies that are no
longer traded. We also picked out a large number of programs where the security
impact of key/IV reuse was minimal or overshadowed by larger security concerns
(for instance, there were a few programs that reused key/IV pairs, but the key
was derived from a 4-digit PIN).
However, one of the programs we found struck us as important: a VPN management
suite.
strongMan VPN Manager
---------------------
strongMan is a web-based management tool for folks using the strongSwan VPN
suite. It allows for credential and user management, initiation of VPN
connections, and more. It’s a pretty slick piece of software; if you’re into
IPsec VPNs, you should definitely give it a look.
strongMan stored PKCS#8-encoded keys in a SQLite database, encrypted with AES.
As you’ve probably guessed, it used pyaes to encrypt them in CTR mode, relying
on the default IV. In PKCS#8 key files, RSA private keys include both the
decryption exponent and the factors of the public modulus. For the same modulus
size, the factors of the modulus will “line up” to start at the same place in
the private key encodings about 99.6% of the time. For a pair of 2048-bit
moduli, we can use the XOR of the factors to recover the factors in a matter
of seconds.
Even worse, the full X.509 certificates were also encrypted using the same
key/IV pair used to encrypt the private keys. Since certificates include a
huge amount of predictable or easily guessable data, it’s easy to recover
the keystream from the known X.509 data, and then use the recovered keystream
to decrypt the private keys without resorting to any fancy XORed-factors
mathematical trickery.
In short, if a hacker could recover a strongMan user’s SQLite file, they
could immediately impersonate anyone whose certificates are stored in the
database and even mount person-in-the-middle attacks. Obviously, this is
not a great outcome.
We privately reported this issue to the strongSwan team. Tobias Brunner,
the strongMan maintainer, provided an absolute model response to a security
issue of this severity. He immediately created a security-fix branch and
collaborated with Trail of Bits to develop stronger protection for his users.
This patch has since been rolled out, and the update includes migration tools
to help users update their old databases to the new format.
Doing it right
--------------
There were several viable approaches to fixing this issue. Adding a unique IV
for each encrypted entry in the database would have allowed strongMan to keep
using pyaes, and would have addressed the immediate issue. But if the code has
to be changed, it may as well be updated to something modern.
After some discussion, several changes were made to the application:
- pyaes was replaced with a library that supports modern cipher modes.
- CTR mode was replaced with GCM-SIV, a cipher mode that includes
authentication tags.
- Tag-checking was integrated into the decryption routines.
- A per-entry key derivation scheme is now used to ensure that key/IV pairs
don’t repeat.
On top of all that, there are now migration scripts to allow strongMan users
to seamlessly update their databases.
There will be a security advisory for strongMan issued in conjunction with this
fix, outlining the nature of the problem, its severity, and the measures taken
to address it. Everything will be out in the open, with full transparency for
all strongMan users.
See the full original blog post for further details and some strong opinions
omitted above.
For the strongMan issue, see:
https://github.com/strongswan/strongMan/security/advisories/GHSA-88w4-jv97-c8xr
--
-Alan Coopersmith- [email protected]
Oracle Solaris Engineering - https://blogs.oracle.com/solaris