Dépassement de tampon du tas dans EPICS Base, corrigé en 7.0.11 (CVE-2026-114595)
Des messages Channel Access non authentifiés corrompent la mémoire d'EPICS Base 7.0.10 et antérieurs ; le lot est corrigé en 7.0.11, aucune exploitation connue.
TL;DR
- Quatre failles de sécurité mémoire dans EPICS Base, le framework open source qui équipe les systèmes de contrôle d'accélérateurs et de télescopes, permettent à un pair réseau non authentifié de corrompre la mémoire d'un Input/Output Controller. La plus grave, CVE-2026-114595, atteint un CVSS v3.1 de 9,8 (Critical). La CISA a publié l'avis ICSA-26-300-01 et Cipher Research a publié les résultats le 27 octobre 2026.
- Toutes les versions d'EPICS Base inférieures ou égales à 7.0.10 sont concernées. Trois failles se trouvent dans l'analyse des messages Channel Access côté serveur sur TCP 5064 ; la quatrième touche la validation de connexion pvAccess classique sur TCP 5075.
- Cipher a démontré une corruption de tas et des plantages en bac à sable, pas d'exécution de code ; l'exécution de code à distance est le potentiel évalué par la CISA. Aucune exploitation n'est connue, et aucun des quatre CVE ne figure au catalogue KEV de la CISA au 3 novembre 2026.
- Mettez à jour chaque déploiement concerné vers EPICS Base 7.0.11, et testez d'abord les anciens clients Channel Access. « Comment corriger ? » détaille les correctifs rétroportés et l'isolement réseau.
Suis-je concerné ?
Vous êtes exposé lorsque toutes ces conditions sont réunies :
- Vous exécutez un Input/Output Controller (IOC) EPICS ou un autre serveur bâti sur EPICS Base 7.0.10 ou antérieur. L'avis de la CISA liste toutes les versions inférieures ou égales à 7.0.10 comme concernées.
- L'attaquant peut joindre les ports de protocole du serveur : Channel Access sur TCP 5064 avec la découverte sur UDP 5064, ou pvAccess classique sur TCP 5075 avec la découverte sur UDP 5076.
- Aucun identifiant n'est requis. Dans la configuration de test de Cipher, aucun compte privilégié n'était nécessaire, et les trois failles Channel Access n'exigent qu'une connexion TCP plus un canal pour les chemins d'écriture.
Les règles d'accès IOC ne changent rien à cela. Elles gouvernent ce qu'un client peut lire ou écrire, et elles ne rendent pas sûre l'analyse d'un message mal formé. La faille pvAccess est atteinte pendant la validation de connexion, avant que cet échange ne se termine.
| Branche | Versions concernées | Version corrigée |
|---|---|---|
| EPICS Base, série 7.0 | 7.0.10 et antérieures | 7.0.11 |
| EPICS Base, séries antérieures, dont 3.x | toutes les versions couvertes par la mention « 7.0.10 and prior » de la CISA | aucune version dédiée ; rétroportez les correctifs 7.0.11 |
Vérifiez ce qui s'exécute sur chaque hôte de l'installation :
# 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'
Les contrôleurs et paquets beamline fournis par des fournisseurs peuvent embarquer EPICS Base : inventoriez-les aussi. Une installation peut exécuter EPICS via une application maintenue en interne pendant qu'une autre le reçoit dans du matériel fournisseur, comme le note Cipher.
Comment corriger ?
Mettez à niveau d'abord, puis vérifiez l'accessibilité des protocoles qui rendait les failles exposées :
- Mettez à jour chaque déploiement de la série 7.0 concerné vers EPICS Base 7.0.11 depuis la page de version EPICS. Les mainteneurs précisent n'avoir pas testé le serveur Channel Access durci avec d'anciens programmes clients : testez les clients anciens à fond avant une mise en production.
- Pour les séries antérieures qui ne peuvent pas passer en 7.0.11, rétroportez les deux correctifs amont : epics-base pull request 934 et pvDataCPP pull request 109. La pull request 934 d’epics-base indique que les rétroportages vers des versions antérieures à 2017 exigent aussi le commit e430d09.
- Restreignez les ports de protocole aux hôtes de contrôle qui en ont besoin pendant le déploiement. Les pratiques recommandées de la CISA s'appliquent : garder les systèmes de contrôle hors d'internet, les isoler des réseaux métier et utiliser des VPN à jour pour l'accès distant nécessaire.
- Si vous packagez EPICS dans un produit, vérifiez si votre copie contient le code Channel Access ou pvAccess classique concerné. Publiez des recommandations ou des correctifs rétroportés par version pour vos clients, comme Cipher le recommande aux mainteneurs aval.
Bloquer les ports réduit l'exposition, ce n'est pas un substitut à la mise à jour. L'IOC continue d'analyser les messages des clients légitimes avec le code vulnérable tant que le correctif n'est pas en place.
Quelle est la cause racine ?
Le serveur Channel Access fait confiance aux nombres d'éléments et aux longueurs fournis par l'en-tête quand il dimensionne et convertit les messages. Le désérialiseur pvAccess classique convertit les éléments décodés vers le type déclaré par le tableau qui les contient, sans vérifier qu'ils l'ont.
Channel Access est le protocole client-serveur historique d'EPICS. L'implémentation serveur, RSRV, lit chaque en-tête de requête dans une structure caHdrLargeArray dont les champs m_dataType, m_count et m_postsize viennent directement du réseau, puis agit dessus dans modules/database/src/ioc/rsrv/camessage.c. Dans le chemin d'écriture de 7.0.10, rien ne recoupe ces champs avec le canal ni avec la charge utile réellement arrivée :
// 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 );
La conversion consomme m_count éléments de type m_dataType depuis le tampon de réception, quel que soit le nombre d'éléments du canal ou d'octets réellement portés par la requête. La boucle de répartition des messages construit aussi des tailles avec une arithmétique 32 bits non vérifiée :
// 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 );
Chacun des quatre CVE est une conséquence de cette confiance, comme l'analyse de Cipher les établit :
- CVE-2026-114595 (CVSS v3.1 9,8, CWE-190) : le nombre d'éléments d'une requête d'écriture est combiné à la taille d'élément sans borne, le calcul déborde de l'arithmétique 32 bits et l'allocation est plus petite que la conversion qui suit. Sous AddressSanitizer, cela a produit une écriture hors limites du tas avec des octets influencés par l'attaquant.
- CVE-2026-114596 (CVSS v3.1 8,2, CWE-190) : une longueur de charge utile en en-tête étendu proche du plafond 32 bits fait déborder le calcul de taille, qui passe le contrôle de taille maximale, et un chemin ultérieur de création de canal écrit un octet terminal hors des limites.
- CVE-2026-114597 (CVSS v3.1 7,5, CWE-130) : le nombre d'éléments déclaré dépasse la charge utile reçue, et la conversion avance au-delà du tampon de réception comme une lecture hors limites.
- CVE-2026-114598 (CVSS v3.1 7,5, CWE-843) : dans
FieldCreate::deserializedepvDataCPP, une description de tableau de structures ou d'unions est acceptée avec un élément d'un type différent, et le code l'interprète selon la mauvaise disposition mémoire, champs porteurs de pointeurs compris.
Comment la faille est-elle exploitée ?
Aucune preuve de concept publique n'existe : Cipher n'a pas publié ses charges de reproduction, et les correctifs amont sont le registre public de ce que chaque correctif ferme. Les étapes ci-dessous sont le mécanisme tel que l'analyse le décrit.
- L'attaquant ouvre une connexion TCP normale vers le port Channel Access de l'IOC et envoie une requête d'écriture dont l'en-tête déclare un grand nombre d'éléments et un type.
- Le nombre d'éléments et la taille d'élément se combinent par une arithmétique 32 bits qui déborde : le serveur alloue trop peu de mémoire pour les données qu'il traite ensuite.
- La conversion de la charge utile de l'attaquant se poursuit dans cette allocation trop petite. Sous AddressSanitizer, la requête a produit une écriture hors limites du tas avec des octets influencés par l'attaquant, suivie d'un plantage du processus.
- La variante en en-tête étendu déclare une longueur de charge utile proche du plafond 32 bits : le contrôle de taille déborde, et un chemin ultérieur de création de canal place un octet terminal au-delà de la mémoire disponible comme une écriture hors limites contrainte.
- La variante de lecture déclare plus d'éléments que la charge utile n'en contient, et la variante pvAccess envoie un élément au mauvais type dans une description de tableau de structures pendant la validation de connexion initiale, avant la fin de l'authentification. Les deux font planter le thread serveur comme lectures hors limites.
Comment se déroule l'attaque ?
Une seule requête d'écriture non authentifiée vers le port Channel Access corrompt le tas de l'IOC via un calcul de dimensionnement qui déborde.
TCP 5064, sans identifiant"] --> B["En-tête de requête d'écriture :
nombre d'éléments choisi pour
faire déborder le calcul"] B --> C["RSRV combine nombre et
taille d'élément sans
recouper le canal ni
la charge utile"] C --> D["Le calcul 32 bits déborde :
tampon alloué trop petit"] D --> E["La conversion écrit les données
de l'attaquant au-delà du tampon"] E --> F["Corruption du tas :
plantage de l'IOC ; exécution
de code potentielle selon la CISA"]
Que peut faire un attaquant ?
Les effets démontrés sont la corruption de mémoire et un déni de service, tous reproduits par Cipher sous AddressSanitizer ou en débogueur :
- CVE-2026-114595 a produit une écriture hors limites du tas avec des octets influencés par l'attaquant, la classe depuis laquelle l'exécution de code à distance se construit. La CISA note la faille Critical avec un impact d'exécution de code potentielle ; Cipher n'a pas construit d'exploit ni évalué la fiabilité de la corruption sur des builds de production.
- CVE-2026-114596 est une écriture hors limites contrainte, un octet fixe à un décalage fixé par le calcul : le résultat est un plantage provoqué à distance plutôt qu'une primitive d'écriture générale.
- CVE-2026-114597 et CVE-2026-114598 sont des lectures hors limites. Cipher a confirmé les plantages et n'a pas démontré de divulgation du contenu mémoire vers un client distant.
Faire planter un IOC a ses propres conséquences opérationnelles. Un IOC assure la surveillance, l'acquisition de données et le contrôle d'équipements dans un instrument plus vaste. L'interrompre peut priver les opérateurs ou l'automatisation d'observations ou de fonctions de contrôle, comme le note l'analyse. La suite dépend de l'architecture de l'installation. Redondance, comportement de repli et verrouillages de protection indépendants décident du rayon d'impact.
Les conditions sont l'accessibilité du port TCP et, pour les chemins d'écriture, un canal : aucun compte privilégié n'était requis dans la configuration de test de Cipher.
Pourquoi le correctif fonctionne-t-il ?
La version 7.0.11 embarque epics-base pull request 934 et pvDataCPP pull request 109, et chacune ferme exactement le manque de validation que sa faille utilisait. Le chemin d'écriture valide désormais le type, borne le nombre d'éléments et compare la taille calculée à la charge utile réellement arrivée :
# 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;
+ }
La boucle de répartition rejette désormais une longueur étendue qui ferait déborder l'arithmétique de taille :
# 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 );
La confusion de types pvAccess est fermée en validant le type réel de l'élément décodé avant la conversion, et la récursion de désérialisation est bornée :
# 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");
La pull request 934 applique la même borne sur le nombre d'éléments et le même recoupement de charge utile aux chemins de lecture, d'ajout d'événement et de notification d'écriture. La recherche de canal rejette aussi les identifiants créés par un autre client : les trois failles Channel Access sont couvertes en un seul jeu de changements. La description de la pull request va dans le même sens : recouper les champs d'en-tête liés msgsize, dtype et count, en évitant avant tout les débordements d'entiers.
Comment vérifier si j'ai été compromis ?
Aucun indicateur n'est publié, car aucune charge de reproduction ni trafic d'attaquant n'a été rendu public. Une tentative échouée peut ne rien laisser d'autre qu'un plantage.
- Passez en revue les enregistrements de disponibilité des IOC pour des redémarrages ou plantages inexpliqués autour des ports de protocole, fichiers core compris sur l'hôte IOC.
- Recherchez des sources inattendues dans les journaux de pare-feu ou de flux pour des connexions vers TCP 5064 ou TCP 5075, et vers la découverte UDP 5064 et 5076, précédant un plantage.
- Vérifiez si un IOC était joignable depuis des segments d'administration, d'accès distant, de recherche, d'invités ou pontés. Cipher les cite nommément comme chemins à revérifier.
- Considérez l'impact de tout événement hors limites confirmé comme inconnu jusqu'à examen. Sans charge publique, aucune empreinte ne distingue une tentative de plantage d'une tentative d'exploitation.
Chronologie
- 2026-06-09 : Causal Security signale les quatre résultats au canal sécurité d'EPICS et coordonne avec la CISA l'attribution des CVE et la notification aux acteurs aval.
- 2026-07-23 : le durcissement Channel Access, epics-base pull request 934, est fusionné dans la branche 7.0 après un rapport confidentiel de Shubham Raj de Cipher et un rapport non confidentiel qui se recoupait.
- 2026-08-10 : le correctif de confusion de types pvAccess, pvDataCPP pull request 109, est fusionné.
- 2026-10-26 : l'archive base-7.0.11.tar.gz et sa signature sont créées depuis la branche 7.0.
- 2026-10-27 : EPICS Base 7.0.11 sort, la CISA publie l'avis ICSA-26-300-01 et Cipher Research publie son analyse.
FAQ
L'exécution de code à distance est-elle démontrée ?
Non. L'avis de la CISA indique que la pire faille « may result in memory corruption, denial of service, or potential remote code execution », et le bac à sable de Cipher a produit une écriture hors limites du tas avec des octets influencés par l'attaquant. Cipher n'a pas construit d'exploit ni évalué la fiabilité de la corruption sur des builds de production : l'exécution de code reste un potentiel évalué, pas un résultat démontré.
L'un des quatre CVE est-il exploité en conditions réelles ?
Aucune exploitation n'est connue, et aucun des quatre n'apparaît au catalogue Known Exploited Vulnerabilities de la CISA au 3 novembre 2026. Les quatre enregistrements CVE ne portent pas non plus de bloc d'évaluation CISA ADP : il n'existe aucun marqueur SSVC d'exploitation à citer.
Les règles d'accès IOC bloquent-elles ces attaques ?
Non. Les règles d'accès gouvernent ce qu'un client peut lire ou écrire, et le protocole de validation de connexion pvAccess fournit une authentification. Cipher dit qu'aucun des deux ne remplace les correctifs : les contrôles ne rendent pas sûre l'analyse d'un message mal formé, et la faille pvAccess est atteinte pendant la validation de connexion avant la fin de cet échange.
Nous exécutons EPICS Base 3.15, pas la série 7.0. Sommes-nous concernés ?
Oui. L'avis de la CISA liste toute version d'EPICS Base inférieure ou égale à 7.0.10 comme concernée. Aucune version de la série 3.15 n'embarque les correctifs : rétroportez epics-base pull request 934 et pvDataCPP pull request 109 ; la première note que les versions antérieures à 2017 exigent aussi le commit e430d09. Les piles empaquetées par des fournisseurs exigent des correctifs fournisseur.
La mise à jour risque-t-elle de casser d'anciens clients Channel Access ?
C'est possible. La page de version 7.0.11 indique que les mainteneurs n'ont pas testé le serveur Channel Access durci avec d'anciens programmes clients. Elle conseille aux sites de tester à fond avant un déploiement en production. Planifiez le déploiement avec l'inventaire des clients anciens en main.
Qui a trouvé ces failles, et comment ?
Shubham Raj de Cipher, le système de sécurité autonome de Causal Security, a trouvé et validé les quatre failles en 3 heures et 49 minutes sur un code qu'il n'avait jamais vu. L'enquête n'a exigé aucune intervention humaine ; la seule étape humaine a été une instruction unique autorisant des tests d'exploitabilité approfondis en bac à sable isolé.
Trouvez les services de contrôle exposés avec Ostorlab
La découverte de la surface d'attaque d'Ostorlab inventorie les hôtes exposés sur internet dans vos plages. Identifiez chaque hôte qui répond sur les ports Channel Access ou pvAccess avant de planifier la fenêtre de mise à jour. Commencez un scan avec Ostorlab pour savoir quels sites corriger en premier.
Références
- Avis CISA pour systèmes de contrôle industriels ICSA-26-300-01, EPICS Base, publié le 27 octobre 2026, avec les descriptions des quatre CVE, vecteurs CVSS et liens de remédiation : https://www.cisa.gov/news-events/ics-advisories/icsa-26-300-01 (vérifié le 3 novembre 2026)
- Cipher Research, Causal Security, « Inside EPICS Base: Four severe vulnerabilities discovered autonomously in under four hours », publié le 27 octobre 2026, avec le mécanisme par faille, les ports et la chronologie de divulgation : https://causalsecurity.com/research/epics-base-security-research (vérifié le 3 novembre 2026)
- Enregistrement CVE-2026-114595 avec CVSS v3.1 9,8 et v4.0 9,3 : https://www.cve.org/CVERecord?id=CVE-2026-114595 (vérifié le 3 novembre 2026)
- Enregistrement CVE-2026-114596 avec CVSS v3.1 8,2 et v4.0 8,8 : https://www.cve.org/CVERecord?id=CVE-2026-114596 (vérifié le 3 novembre 2026)
- Enregistrement CVE-2026-114597 avec CVSS v3.1 7,5 et v4.0 8,7 : https://www.cve.org/CVERecord?id=CVE-2026-114597 (vérifié le 3 novembre 2026)
- Enregistrement CVE-2026-114598 avec CVSS v3.1 7,5 et v4.0 8,7 : https://www.cve.org/CVERecord?id=CVE-2026-114598 (vérifié le 3 novembre 2026)
- epics-base pull request 934, « RSRV message validation », fusionnée le 23 juillet 2026, correctif Channel Access avec la note de rétroportage pour les versions antérieures à 2017 : https://github.com/epics-base/epics-base/pull/934 (vérifié le 3 novembre 2026)
- pvDataCPP pull request 109, correctif de validation de type et de bornage de récursion pour pvAccess, fusionné le 10 août 2026 : https://github.com/epics-base/pvDataCPP/pull/109 (vérifié le 3 novembre 2026)
- Page de version EPICS 7.0.11, 26 octobre 2026, avec l'avertissement d'interopérabilité clients anciens et les liens de téléchargement : https://epics-controls.org/resources-and-support/base/epics-7/7-0-11/ (vérifié le 3 novembre 2026)
- Version GitHub EPICS Base R7.0.11, publiée le 27 octobre 2026 : https://github.com/epics-base/epics-base/releases/tag/R7.0.11 (vérifié le 3 novembre 2026)
- Source vulnérable, camessage.c au tag R7.0.10, citée pour la section cause racine : https://github.com/epics-base/epics-base/blob/R7.0.10/modules/database/src/ioc/rsrv/camessage.c (vérifié le 3 novembre 2026)
- Flux JSON du catalogue Known Exploited Vulnerabilities de la CISA, recherché pour les quatre CVE sans correspondance au 3 novembre 2026 : https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json (vérifié le 3 novembre 2026)