Neutron, our AI engine, scored 97.1% on UC Berkeley's CyberGym benchmark. Learn more

Deep Dive

Deep Dive

EPICS Base Heap Overflow, Fixed in 7.0.11 (CVE-2026-114595)

Unauthenticated Channel Access messages corrupt memory in EPICS Base 7.0.10 and earlier; the batch is fixed in 7.0.11, and no exploitation is known.

TL;DR

  • Four memory-safety flaws in EPICS Base, the open-source framework behind accelerator and telescope control systems, let an unauthenticated network peer corrupt an Input/Output Controller's memory. The worst, CVE-2026-114595, is CVSS v3.1 9.8 Critical. CISA published advisory ICSA-26-300-01 and Cipher Research published the findings on October 27, 2026.
  • Every EPICS Base release at or below 7.0.10 is affected. Three flaws sit in server-side Channel Access parsing on TCP 5064; the fourth hits classic pvAccess connection validation on TCP 5075.
  • Cipher demonstrated heap corruption and crashes in a sandbox, not code execution; remote code execution is CISA's assessed potential. No exploitation is known, and none of the four CVEs is in CISA's Known Exploited Vulnerabilities catalog as of November 3, 2026.
  • Update every affected deployment to EPICS Base 7.0.11, and test older Channel Access clients before deploying it. "How do I fix it?" carries the backport and network-segregation steps.

Am I affected?

You are exposed when all of these hold:

  • You run an EPICS Input/Output Controller (IOC) or another server built on EPICS Base 7.0.10 or earlier. CISA's advisory lists every release at or below 7.0.10 as affected.
  • The attacker can reach the server's protocol ports: Channel Access on TCP 5064 with discovery on UDP 5064, or classic pvAccess on TCP 5075 with discovery on UDP 5076.
  • No credential is required. In Cipher's test configuration no privileged account was needed, and the three Channel Access flaws need only a TCP connection plus a channel for the write paths.

IOC access-security rules do not change this. They govern what a client may read or write, and they do not make a malformed message safe to parse. The pvAccess flaw is reached during connection validation, before that exchange completes.

Branch Affected versions Fixed version
EPICS Base, 7.0 series 7.0.10 and earlier 7.0.11
EPICS Base, older series, including 3.x all releases covered by CISA's "7.0.10 and prior" line no dedicated release; backport the 7.0.11 fixes

Check what you run on each facility host:

# In each EPICS Base installation: the generated version header
grep EPICS_VERSION_SHORT <epics-base>/include/epicsVersion.h

# In each IOC application directory: which EPICS Base it builds against
grep -n "EPICS_BASE" configure/RELEASE

# On the IOC host: which processes serve Channel Access and pvAccess
ss -tlnp | grep -E ':5064|:5075'

Vendor-supplied controllers and beamline packages can embed EPICS Base, so inventory those too. A facility may run EPICS through an internally maintained application while another receives it inside vendor hardware, as Cipher notes.

How do I fix it?

Upgrade first, then verify the protocol reachability that made the flaws exposed:

  1. Update every affected 7.0-series deployment to EPICS Base 7.0.11 from the EPICS controls release page. The maintainers warn that they have not tested the hardened Channel Access server with older client programs, so test legacy clients thoroughly before production deployment.
  2. For older series that cannot move to 7.0.11, backport the two upstream fixes: epics-base pull request 934 and pvDataCPP pull request 109. The epics-base pull request 934 notes that backports to releases before 2017 also need commit e430d09.
  3. Restrict the protocol ports to the control hosts that need them while you roll out. CISA's recommended practices apply: keep control systems off the internet, isolate them from business networks, and use VPNs for required remote access, updated to their current versions.
  4. If you package EPICS into a product, verify whether your copy includes the affected Channel Access or classic pvAccess code. Publish version-specific guidance or backports for your customers, as Cipher recommends to downstream maintainers.

Blocking the ports is an exposure reduction, not a substitute for the update. The IOC still parses messages from legitimate clients with the vulnerable code until the fix is in.

What is the root cause?

The Channel Access server trusts header-supplied element counts and lengths when it sizes and converts messages. The classic pvAccess deserializer casts decoded elements to the type the enclosing array declares, without checking that they have it.

Channel Access is EPICS' original client-server protocol. The server-side implementation, RSRV, reads each request header into a caHdrLargeArray whose m_dataType, m_count and m_postsize fields come straight from the network, then acts on them in modules/database/src/ioc/rsrv/camessage.c. In the 7.0.10 write path, nothing cross-checks those fields against the channel or the payload that actually arrived:

// epics-base/modules/database/src/ioc/rsrv/camessage.c at R7.0.10 (write_action)
status = caNetConvert (
    mp->m_dataType, pPayload, pPayload,
    FALSE /* net -> host format */, mp->m_count );

The conversion consumes m_count elements of m_dataType from the receive buffer regardless of how many elements the channel holds or how many bytes the request actually carried. The message-dispatch loop builds sizes with unchecked 32-bit arithmetic as well:

// epics-base/modules/database/src/ioc/rsrv/camessage.c at R7.0.10 (camessage)
msg.m_postsize  = ntohl ( pLW[0] );
msg.m_count     = ntohl ( pLW[1] );
msgsize = msg.m_postsize + sizeof(*mp) + 2 * sizeof ( *pLW );

Each of the four CVEs is one consequence of that trust, as Cipher's analysis maps them:

  • CVE-2026-114595 (CVSS v3.1 9.8, CWE-190): a write request's element count is combined with the element size without a bound, the calculation overflows 32-bit arithmetic, and the allocation is smaller than the conversion that follows. Under AddressSanitizer this produced a heap-buffer-overflow write of attacker-influenced bytes.
  • CVE-2026-114596 (CVSS v3.1 8.2, CWE-190): an extended-header payload length near the 32-bit ceiling makes the calculated message size wrap and pass the too-large check, and a later channel-creation path writes a terminating byte out of bounds.
  • CVE-2026-114597 (CVSS v3.1 7.5, CWE-130): the declared element count exceeds the received payload, and conversion advances past the receive buffer as an out-of-bounds read.
  • CVE-2026-114598 (CVSS v3.1 7.5, CWE-843): in pvDataCPP's FieldCreate::deserialize, an array-of-structure or array-of-union description is accepted with an element of a different type, and the code interprets it through the wrong layout, including pointer-bearing fields.

The four flaws by CVSS v3.1 base score: 9.8, 8.2, 7.5 and 7.5, one Critical and three High
Figure 1: the four EPICS Base flaws by CVSS v3.1 base score, one Critical and three High. Source: CISA advisory ICSA-26-300-01, checked November 3, 2026

How is it exploited?

No public proof of concept exists: Cipher did not publish its reproduction payloads, and the upstream patches are the public record of what each fix closes. The steps below are the mechanism as the analysis describes it.

  1. The attacker opens a normal TCP connection to the IOC's Channel Access port and sends a write request whose header declares a large element count and type.
  2. The count and element size combine through 32-bit arithmetic that wraps, so the server allocates too little memory for the data it then processes.
  3. Conversion of the attacker's payload proceeds into that undersized allocation. Under AddressSanitizer the request produced a heap-buffer-overflow write of attacker-influenced bytes, followed by a process crash.
  4. The extended-header variant declares a payload length near the 32-bit ceiling, so the size check wraps. A later channel-creation path then places a terminating byte beyond available memory as a constrained out-of-bounds write.
  5. The read variant declares more elements than the payload holds, and the pvAccess variant sends a wrongly typed element inside an array-of-structure description during early connection validation, before authentication completes. Both fault the server thread as out-of-bounds reads.

How does the attack flow?

One unauthenticated write request to the Channel Access port corrupts the IOC's heap through a wrapped sizing calculation.

flowchart LR A["Attacker connects to
TCP 5064, no credentials"] --> B["Write request header:
element count chosen
to overflow the sizing math"] B --> C["RSRV combines count and
element size with no
cross-check against
the channel or payload"] C --> D["32-bit calculation wraps:
buffer allocated too small"] D --> E["Conversion writes attacker data
past the undersized buffer"] E --> F["Heap corruption:
IOC crashes; potential
code execution per CISA"]

What can an attacker do?

The demonstrated effects are memory corruption and denial of service, all reproduced by Cipher under AddressSanitizer or a debugger:

  • CVE-2026-114595 produced a heap-buffer-overflow write of attacker-influenced bytes, the class from which remote code execution is built. CISA rates the issue Critical with a potential-code-execution impact; Cipher did not build an exploit or evaluate reliability on production builds.
  • CVE-2026-114596 is a constrained out-of-bounds write, a fixed byte at an offset set by the calculation, so the outcome is a remotely induced crash rather than a general write primitive.
  • CVE-2026-114597 and CVE-2026-114598 are out-of-bounds reads. Cipher confirmed the crashes and did not demonstrate disclosure of memory contents to a remote client.

Crashing an IOC has operational consequences of its own. An IOC performs monitoring, data acquisition and control of equipment within a larger instrument. Interrupting it may deprive operators or automation of observations or control functions, as the analysis notes. What happens next depends on the facility's architecture. Redundancy, fail-safe behavior and independent protection interlocks decide the blast radius.

The conditions are reachability of the TCP port and, for the write paths, a channel: no privileged account was required in Cipher's test configuration.

Why does the fix work?

The 7.0.11 release carries epics-base pull request 934 and pvDataCPP pull request 109, and each closes the exact validation gap its flaw used. The write path now validates the type, caps the count and compares the computed size against the payload that actually arrived:

 # epics-base/modules/database/src/ioc/rsrv/camessage.c (write_action, PR 934)
-    pciu = MPTOPCIU(mp);
+    pciu = MPTOPCIU(mp, client);
     if(!pciu){
         logBadId(client, mp, pPayload);
         return RSRV_ERROR;
     }
+
+    if (INVALID_DB_REQ(mp->m_dataType)) {
+        log_header ("bad put data type", client, mp, pPayload, 0);
+        return RSRV_ERROR;
+    }
+    if (mp->m_count > dbChannelFinalElements(pciu->dbch)) {
+        mp->m_count = dbChannelFinalElements(pciu->dbch);
+    }
+
+    size = dbr_size_n (mp->m_dataType, mp->m_count);
+    if (size > mp->m_postsize) {
+        return RSRV_ERROR;
+    }

The message-dispatch loop now rejects an extended length that would wrap the size arithmetic:

 # epics-base/modules/database/src/ioc/rsrv/camessage.c (camessage, PR 934)
             msg.m_postsize  = ntohl ( pLW[0] );
             msg.m_count     = ntohl ( pLW[1] );
+            if (msg.m_postsize >= ca_uint32_max - (sizeof(*mp) + 2 * sizeof ( *pLW ))) {
+                if(CASDEBUG>0) {
+                    errlogPrintf("Client ext msg size too large 0x%08x\n",
+                                 (unsigned)msg.m_postsize);
+                }
+                status = RSRV_ERROR;
+                break;
+            }
             msgsize = msg.m_postsize + sizeof(*mp) + 2 * sizeof ( *pLW );

The pvAccess type confusion is closed by validating the decoded element's actual type before the cast, and deserialization recursion is bounded:

 # pvDataCPP/src/factory/FieldCreateFactory.cpp (FieldCreate::deserialize, PR 109)
-            StructureConstPtr elementStructure = std::tr1::static_pointer_cast<const Structure>(control->cachedDeserialize(buffer));
+            StructureConstPtr elementStructure = std::tr1::dynamic_pointer_cast<const Structure>(control->cachedDeserialize(buffer));
+            if(!elementStructure)
+                throw std::invalid_argument("Expected Structure");

Pull request 934 applies the same count cap and payload cross-check to the read, event-add and write-notify paths. The channel lookup now also rejects identifiers minted by a different client, so the three Channel Access flaws are covered in one change set. The pull request's own description matches this: cross-checking between the interrelated msgsize, dtype and count header fields, principally avoiding integer overflows.

How do I check if I was compromised?

No indicators are published, because no reproduction payloads or attacker traffic have been released. A failed attempt may leave nothing beyond a crash.

  • Review IOC availability records for unexplained restarts or process crashes around the protocol ports, including core files on the IOC host.
  • Hunt unexpected sources in firewall or flow logs for connections to TCP 5064 or TCP 5075, and to UDP 5064 and 5076 discovery, that precede any crash.
  • Ask whether any IOC was reachable from management, remote-access, research, guest or bridged network segments. Cipher specifically calls these out as paths to re-check.
  • Treat the impact of any confirmed out-of-bounds event as unknown until examined. With no public payload, there is no fingerprint that distinguishes an attempted crash from an exploitation attempt.

Timeline

  • 2026-06-09: Causal Security reports the four findings to the EPICS security channel and coordinates with CISA on CVE assignment and downstream notification.
  • 2026-07-23: The Channel Access hardening, epics-base pull request 934, is merged into the 7.0 branch after a confidential report from Shubham Raj of Cipher and an overlapping non-confidential report.
  • 2026-08-10: The pvAccess type-confusion fix, pvDataCPP pull request 109, is merged.
  • 2026-10-26: The base-7.0.11 release tarball and its signature are created from the 7.0 branch.
  • 2026-10-27: EPICS Base 7.0.11 is released, CISA publishes advisory ICSA-26-300-01, and Cipher Research publishes its analysis.

From the confidential report to the fixed release and the CISA advisory, 140 days, with the Channel Access fix merged on day 44
Figure 2: from the June 9, 2026 confidential report to the 7.0.11 release and CISA advisory on October 27, 2026, 140 days, with the Channel Access fix merged on day 44. Source: Cipher Research and the EPICS 7.0.11 release page, checked November 3, 2026

FAQ

Is remote code execution demonstrated?

No. CISA's advisory states the worst flaw "may result in memory corruption, denial of service, or potential remote code execution", and Cipher's sandbox produced an attacker-influenced heap-buffer-overflow write. Cipher did not build an exploit or evaluate corruption reliability on production builds, so code execution remains an assessed potential, not a demonstrated outcome.

Are any of the four CVEs exploited in the wild?

No exploitation is known, and none of the four appears in CISA's Known Exploited Vulnerabilities catalog as of November 3, 2026. The four CVE records carry no CISA ADP assessment block either, so there is no SSVC exploitation marker to cite.

Do IOC access-security rules stop these attacks?

No. Access-security rules govern what a client may read or write, and the pvAccess connection-validation protocol provides authentication. Cipher states that neither substitute for the fixes. The controls do not make a malformed message safe to parse, and the pvAccess flaw is reached during connection validation before that exchange completes.

We run EPICS Base 3.15, not the 7.0 series. Are we affected?

Yes. CISA's advisory lists every EPICS Base release at or below 7.0.10 as affected. No 3.15-series release carries the fixes, so backport epics-base pull request 934 and pvDataCPP pull request 109; the former notes that releases before 2017 also need commit e430d09. Vendor-packaged stacks need vendor backports.

Will the update break older Channel Access clients?

It may. The 7.0.11 release page states that the maintainers have not tested the hardened Channel Access server with older client programs. It advises sites to test thoroughly before production deployment. Plan the rollout with your legacy client inventory in hand.

Who found these flaws, and how?

Shubham Raj of Cipher, Causal Security's autonomous security system, found and validated all four in 3 hours and 49 minutes on a codebase it had not seen before. The investigation required no human intervention; the one human step was a single instruction authorizing deeper exploitability testing in an isolated sandbox.

Find exposed control-system services with Ostorlab

Ostorlab's attack surface discovery inventories the internet-facing hosts in your ranges. Find every host answering on the Channel Access or pvAccess ports before you plan the upgrade window. Start a scan with Ostorlab to know which sites need the update first.

References

  • CISA industrial control systems advisory ICSA-26-300-01, EPICS Base, published October 27, 2026, with the four CVE descriptions, CVSS vectors and remediation links: https://www.cisa.gov/news-events/ics-advisories/icsa-26-300-01 (checked November 3, 2026)
  • Cipher Research, Causal Security, "Inside EPICS Base: Four severe vulnerabilities discovered autonomously in under four hours", published October 27, 2026, with the per-flaw mechanism, ports and disclosure timeline: https://causalsecurity.com/research/epics-base-security-research (checked November 3, 2026)
  • CVE-2026-114595 record with CVSS v3.1 9.8 and v4.0 9.3: https://www.cve.org/CVERecord?id=CVE-2026-114595 (checked November 3, 2026)
  • CVE-2026-114596 record with CVSS v3.1 8.2 and v4.0 8.8: https://www.cve.org/CVERecord?id=CVE-2026-114596 (checked November 3, 2026)
  • CVE-2026-114597 record with CVSS v3.1 7.5 and v4.0 8.7: https://www.cve.org/CVERecord?id=CVE-2026-114597 (checked November 3, 2026)
  • CVE-2026-114598 record with CVSS v3.1 7.5 and v4.0 8.7: https://www.cve.org/CVERecord?id=CVE-2026-114598 (checked November 3, 2026)
  • epics-base pull request 934, "RSRV message validation", merged July 23, 2026, the Channel Access fix with the backport note for releases before 2017: https://github.com/epics-base/epics-base/pull/934 (checked November 3, 2026)
  • pvDataCPP pull request 109, the pvAccess deserialization type-validation and recursion fix, merged August 10, 2026: https://github.com/epics-base/pvDataCPP/pull/109 (checked November 3, 2026)
  • EPICS 7.0.11 release page, October 26, 2026, with the older-client interoperability warning and download links: https://epics-controls.org/resources-and-support/base/epics-7/7-0-11/ (checked November 3, 2026)
  • EPICS Base R7.0.11 GitHub release, published October 27, 2026: https://github.com/epics-base/epics-base/releases/tag/R7.0.11 (checked November 3, 2026)
  • Vulnerable source, camessage.c at tag R7.0.10, quoted for the root-cause section: https://github.com/epics-base/epics-base/blob/R7.0.10/modules/database/src/ioc/rsrv/camessage.c (checked November 3, 2026)
  • CISA Known Exploited Vulnerabilities catalog JSON feed, searched for all four CVEs with no match as of November 3, 2026: https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json (checked November 3, 2026)