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, linked libssl, strings output, 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.md when 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