OpenSSL 3.0.7: The Critical Bug That Wasn't, and Why the Fire Drill Still Paid Off
OpenSSL pre-announced a critical fix, then shipped two high-severity bugs instead. How to find every OpenSSL 3 copy you run, and why the inventory matters.
Want this checked continuously?
CompleteStatus grades your headers, SSL and email security 24/7 — free, commercial use allowed.
For a week, a lot of operations teams had a date circled on the calendar. On October 25, the OpenSSL project gave advance notice that version 3.0.7 would ship on November 1 with a fix for a vulnerability rated critical. That word carries weight: the last critical OpenSSL advisory was back in 2016, and the bug everyone still measures OpenSSL problems against is Heartbleed. People cleared their schedules.
Then November 1 arrived, and the release notes said something different. The fix covered two vulnerabilities, CVE-2022-3602 and CVE-2022-3786, and both had been downgraded to high. Plenty of people exhaled, some grumbled about crying wolf, and a few decided the whole thing had been a waste of a week.
We'd argue the opposite. The bug turned out to be less dangerous than feared, but the week of preparation exposed something much more useful: most teams had no quick answer to "where are we running OpenSSL 3?"
What the bugs actually are
Both issues are buffer overruns in X.509 certificate verification, specifically in the code that checks email-address name constraints (the punycode decoding path). CVE-2022-3602 lets an attacker overwrite four bytes on the stack; CVE-2022-3786 allows an arbitrary number of . characters to be written, which is more of a crash-the-process problem.
Why the downgrade? According to the OpenSSL advisory, a few things made exploitation much harder than first assessed:
- The vulnerable code runs after the certificate chain's signature is verified. So an attacker needs either a malicious certificate signed by a CA you trust, or an application that keeps going after failing to build a path to a trusted issuer.
- Many modern platforms build with stack-overflow protections that turn the four-byte overwrite into a crash rather than code execution.
- Some early analysis from vendors and researchers suggested the stack layout on common Linux builds made remote code execution unlikely.
So in practice this looks mostly like a denial-of-service risk for clients that verify certificates, and for servers that ask clients for certificates (mutual TLS). Still worth patching promptly. Not Heartbleed.
Who's affected
Only the OpenSSL 3.0 branch: versions 3.0.0 through 3.0.6. OpenSSL 1.1.1 and 1.0.2 are not affected. That narrows things a lot, because 1.1.1 is still what most production servers run.
OpenSSL 3.0 only came out in September 2021, so the exposure is concentrated in newer places:
- Recent distributions that ship 3.0 as the system library, such as Ubuntu 22.04 and RHEL 9, along with Fedora and other fast-moving distros.
- Container images built on those base images.
- Software that bundles its own OpenSSL, including recent Node.js releases (Node 18 ships with OpenSSL 3, and the Node project put out security releases alongside the OpenSSL fix).
- Statically linked binaries and vendor appliances, which are the hard part.
Finding OpenSSL 3 on your systems
The system library is the easy case:
# What the CLI says (not always the same as what apps load)
openssl version
# Debian / Ubuntu: OpenSSL 3 ships as libssl3
dpkg -l | grep -E 'libssl3|openssl'
# RHEL / Fedora
rpm -q openssl openssl-libs
Then find processes that actually have it loaded, which is what matters until they restart:
# Processes with libssl.so.3 mapped into memory
sudo grep -l 'libssl.so.3' /proc/*/maps 2>/dev/null | cut -d/ -f3 | sort -u | \
xargs -r ps -o pid,comm -p
For containers, check each image rather than assuming the host covers it:
for img in $(docker images --format '{{.Repository}}:{{.Tag}}'); do
echo -n "$img: "
docker run --rm --entrypoint sh "$img" -c 'openssl version 2>/dev/null || echo "no openssl cli"'
done
An image without the openssl binary can still contain libssl.so.3, so a file search inside the image is more reliable if you have time. For bundled runtimes, ask the runtime directly:
node -p "process.versions.openssl"
python3 -c "import ssl; print(ssl.OPENSSL_VERSION)"
And for statically linked binaries, the crude approach works surprisingly often:
strings /path/to/binary | grep -E '^OpenSSL 3\.0\.[0-6] '
Vendor appliances, load balancers and anything closed-source need a vendor answer. Expect a trickle of advisories over the next few weeks.
Don't forget the restart
Upgrading the package does nothing for a process that loaded the old library at startup. After updating, restart the services that link against it (web servers, proxies, language runtimes, anything doing TLS), or reboot. On Debian-family systems, needrestart will list what's still using deleted library files; on RHEL, needs-restarting -s does the same job.
The real lesson: the inventory
The most useful thing that happened last week wasn't the patch. It was thousands of teams discovering, under mild time pressure, how long it took to answer a simple question about their own estate. Some had an answer in minutes from an SBOM or a package inventory. Many spent days grepping servers and chasing container images, and some still aren't sure.
That's the same gap Log4Shell exposed last December, and it's the gap behind almost every "the patch existed for months" story, from WannaCry to Equifax. The severity of the next bug is out of your control. How fast you can find every affected copy is entirely in it.
Things worth doing while last week is still fresh:
- Keep a software inventory you can query. Package lists from every host, and an SBOM or at least a dependency list for every container image you build. Store it somewhere searchable.
- Record base images. Knowing that twenty services are built on the same base image turns twenty investigations into one.
- Treat pre-announcements as a gift. OpenSSL gave a week's notice. Use that kind of window to run the inventory, not to wait for the details.
- Write down what you did. The commands above, adapted to your environment, belong in a runbook. The next pre-announcement will not be downgraded.
Keep watching the outside too
Inventory tells you what's installed. It's also worth knowing what your public endpoints actually present to the world: which TLS versions they negotiate, which certificates they serve and when those expire. CompleteStatus checks that from the outside, which is a handy cross-check that the servers you patched are the ones answering on your domain.
Written with AI assistance and reviewed by the CompleteStatus team.
Get notified when CompleteStatus opens
New accounts are closed while we're in private beta. Leave your email and we'll send one message the moment sign-ups open — nothing else.