Skip to content

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.

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.

Related