CVE-2014-0160 — Heartbleed
A missing length check in OpenSSL’s TLS heartbeat extension let an attacker request up to 64KB of process memory per heartbeat — keys, session tokens, decrypted plaintext, anything the OpenSSL process happened to have in its address space. The “we patched it” announcement is what most people remember; the durable lesson is that patching wasn’t the fix. Rotating every key and revoking every cert that lived through the vulnerable window was the fix. A decade later this is still the most-cited reason post-incident playbooks demand key rotation, not just patching.
Affected versions
- OpenSSL 1.0.1 through 1.0.1f — vulnerable.
- OpenSSL 1.0.1g+ — patched.
- OpenSSL ≤1.0.0 / ≥1.0.2 — not affected.
- LibreSSL, BoringSSL, Java’s JSSE, Go’s
crypto/tls, Microsoft Schannel — not affected (different stacks).
Indicator-of-exposure
The system was exposed if it ran OpenSSL in the affected range and had the heartbeat extension enabled (the default for affected versions). Detection commands:
openssl version
# or, for an installed binary:
strings /usr/bin/openssl | grep -i 'OpenSSL 1\.0\.1'
For services: any TLS-terminating daemon (HTTPS server,
mail server, VPN) compiled against affected OpenSSL was
exposed. A heartbeat scan
(openssl s_client -connect host:443 -tlsextdebug | grep heartbeat) confirms whether the server still negotiated the
extension.
This CVE is over a decade old. Any system still in the affected range today is also missing a decade of unrelated patches; treat the finding as a tip-of-the-iceberg signal, not just a single-CVE fix.
Remediation strategy
- Upgrade to a current OpenSSL (the 3.x branch by 2026). 1.0.1g was the immediate patch; the durable answer is current.
- Disable the TLS heartbeat extension in any service that doesn’t actively use it (most don’t). Defence-in-depth.
- Rotate every private key, session secret, API token, and password whose plaintext could have been in the process memory of an affected daemon during the exposure window.
- Revoke every TLS certificate generated using a private key that was on an affected host.
- Audit for unexplained authentication sessions during the exposure window.
For systems running OpenSSL 1.0.1 today: this is not a single-CVE fix. The right shape is a runtime upgrade. Treat this recipe as the trigger; the workflow is broader.
When to use it
Use this recipe when a host, container image, appliance, embedded service,
runtime bundle, or TLS-terminating application may run OpenSSL 1.0.1 through
1.0.1f, statically link affected OpenSSL, or carry a legacy libssl in a
language/runtime distribution. It is most important when the service was
network-exposed during the vulnerable window or held TLS keys, session secrets,
tokens, or plaintext user data in process memory.
Use it to separate the package/runtime upgrade from the required incident response work: key rotation, certificate revocation, session invalidation, secret rotation, service restart, and exposure-window audit. Do not use it as a routine dependency bump when exposure is confirmed.
Inputs
- Host inventories, container images, SBOMs, base-image manifests, package locks, runtime bundles, statically linked binaries, TLS service manifests, load balancer/proxy config, VPN/mail/web server config, and deployment runbooks.
- OpenSSL version evidence from package managers,
openssl version, linkedlibssl,stringsoutput, image scans, SCA/SBOM reports, and appliance or vendor advisories. - Exposure evidence: public/internal network reachability, heartbeat-extension scan results, service start/stop history, patch timing, affected daemon list, log retention, certificate/key locations, and session/token lifetimes.
- Operator-owned secrets reachable by affected processes: TLS private keys, certificates, session signing/encryption keys, API tokens, database passwords, OAuth client secrets, build credentials, and cached sessions.
- Change-control and IR constraints for service restarts, key rotation, certificate reissue/revocation, CRL/OCSP propagation, global logout, and artifact rebuilds.
The prompt
You are remediating CVE-2014-0160 (Heartbleed) on this host
or in this system image. Output exactly one of:
- A PR / change request upgrading the OpenSSL runtime, plus
an incident-response checklist for the operator.
- A TRIAGE.md if the host has been running an affected
OpenSSL with public exposure for an extended period.
This recipe is **not** a routine package bump. If exposure
is confirmed, do not auto-remediate; produce the incident
checklist and stop.
## Step 0 — Detect
1. Read the OpenSSL version: `openssl version`. Read every
service binary's linked OpenSSL: `ldd <binary> | grep ssl`,
then `strings <libssl> | grep -i 'OpenSSL 1\\.0\\.'`.
2. For every TLS-terminating service on the host
(HTTPS server, mail, VPN, internal RPC), test for the
heartbeat extension:
`openssl s_client -connect host:port -tlsextdebug 2>&1 | grep -i heartbeat`.
3. Determine the host's exposure window (when the affected
OpenSSL was first installed; when network-exposed
services using it were started).
## Step 1 — Classify
- **Never network-exposed during exposure window:** Upgrade
the package, rotate any local keys, document.
- **Network-exposed during exposure window:** Treat as
compromised. Write the IR checklist; do not auto-remediate
the keys; only the package upgrade is in scope for the
agent.
## Step 2 — Upgrade
1. For modern distros, upgrade via the package manager:
`apt upgrade openssl libssl3 libssl1.1 libssl1.0.0`,
`dnf upgrade openssl openssl-libs`, etc. — to the
current 3.x branch on systems that support it.
2. Restart every service that links the upgraded OpenSSL.
The agent lists the services to restart in the PR body;
the operator runs the restart.
3. Re-run the heartbeat detection from Step 0 against every
service. The extension should be absent or harmless on
patched OpenSSL.
## Step 3 — Disable the heartbeat extension (defence-in-depth)
For any TLS-terminating service that does not use heartbeats:
- nginx, Apache, HAProxy, etc. — set the OpenSSL ciphers
list / disable heartbeats per the service's
configuration. Most modern configs already exclude it.
## Step 4 — IR checklist (for compromised classification)
The TRIAGE.md must include:
- Rotate every TLS private key on the host.
- Revoke and re-issue every certificate generated from those
keys. Confirm CRL / OCSP propagation.
- Rotate every long-lived secret accessible from the
compromised process: DB passwords, API keys, OAuth
client secrets, session-encryption keys.
- Invalidate every session token that pre-dates the rotation.
- Audit the auth logs for unexplained sessions during the
exposure window.
- Rebuild any artefacts produced on the host during the
window if the build process touched secrets.
## Stop conditions
- The system runs an OpenSSL old enough to indicate broader
patching gaps. Triage with a recommendation for a
comprehensive runtime upgrade, not just OpenSSL.
- A service depends on the heartbeat extension for a real
reason (rare). Document and triage.
- The host's exposure window is unclear from available logs.
Triage.
## Scope
- Do not rotate keys or revoke certs — those are operator
actions on the IR checklist.
- Do not modify TLS configurations outside the documented
defence-in-depth scope.
- Do not bundle unrelated CVE fixes.
Verification — what the reviewer looks for
- The OpenSSL runtime version after upgrade is on the current 3.x branch (or the distro’s currently-supported branch).
- Every service listed in the PR was restarted.
- The heartbeat scan shows the extension absent or harmless on every service.
- For compromised classification: the IR checklist was followed end-to-end. A package upgrade alone is not sufficient.
- The PR includes an honest assessment of the exposure window and the artefacts/services that depended on potentially-leaked secrets.
Watch for
- Statically-linked OpenSSL. A package upgrade doesn’t fix a service that bakes its own OpenSSL into a static binary. Identify and rebuild every such binary.
- Bundled OpenSSL in language runtimes. Older Python / Ruby / Node distributions sometimes ship their own OpenSSL. Upgrade the runtime, not just the system package.
- Long-lived sessions. A web session minted during the exposure window could still be active. Force a global re-login if the application’s session lifetime is long.
- Certificate revocation in practice. CRLs and OCSP can be slow. Many clients ignore revocation entirely. The durable defence is short-lived certs (ACME with renewal), not relying on revocation propagation.
- Internal services. Heartbleed exposure on an internal service is still exposure. “Behind the firewall” is not a control if any compromised internal client could have scanned.
Output contract
Return one of:
- A reviewer-ready PR/change request that upgrades the controlled OpenSSL runtime or image, identifies every affected TLS-terminating service, lists restart requirements, verifies heartbeat exposure is absent or harmless after patching, and attaches an operator incident-response checklist.
TRIAGE.mdwhen network exposure is confirmed or unclear, an affected statically linked/runtime-bundled OpenSSL cannot be patched in this repository, a broader unsupported-runtime upgrade is required, or key/cert rotation and exposure-window analysis must precede code changes.
The output must list affected OpenSSL versions, services, images or binaries, exposure window, network reachability, restart plan, heartbeat validation, keys/certs/secrets requiring rotation, certificates requiring revocation, and sessions/artifacts requiring invalidation or rebuild. It must not claim a package upgrade alone fixes exposed Heartbleed, rotate production keys without operator approval, or bundle unrelated CVE upgrades.
References
- NVD: https://nvd.nist.gov/vuln/detail/CVE-2014-0160
- CVE record: https://www.cve.org/CVERecord?id=CVE-2014-0160
Related recipes
- Vulnerable Dependency Remediation — generic CVE workflow.
- Base Image & Container Layer Remediation — when OpenSSL is in a container base image.