Trouvé à 2 h du matin, en lisant du source ESP-TEE que je n’avais aucune raison de lire. Une ligne semblait bancale. Elle l’était, à un seul caractère près. Ce caractère avait rouvert un CVSS 9.3, à l’intérieur même du correctif censé le fermer.
TL;DR
Deux failles jumelles dans les wrappers de services sécurisés ESP-TEE. Même code, primitives opposées.
L’écriture (CVE-2026-45328, CVSS 9.3 critique, CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H ; le terme C:H est le pire cas chaîné, voir la section impact). Sa cause racine est une validation de pointeurs incomplète. Espressif l’a corrigée, puis un commit oublié a rouvert l’écriture en v6.0.1 : un seul caractère, = au lieu de &= dans _ss_esp_tee_sec_storage_aead_encrypt(), transforme en dead-store la chaîne de validation de pointeurs à cinq termes dès que aad_len != 0. Une application REE pointe l’argument iv vers la mémoire M-mode du TEE ; le TEE appelle ensuite esp_fill_random(iv, iv_len) avant l’exécution du corps AEAD, écrivant un nombre d’octets aléatoires contrôlé par l’attaquant à l’adresse TEE choisie par l’attaquant.
La lecture (CVE-2026-45329, CVSS 7.1, élevée). Plusieurs de ces mêmes wrappers ne valident que certains des arguments pointeurs, laissant des pointeurs d’entrée non vérifiés. Une application REE pointe une entrée vers la mémoire exclusive au TEE ; un périphérique crypto/stockage (ECC, SHA, ou le chemin SPI/flash) tournant en M-mode la lit et renvoie sa sortie au REE, exposant du code, des données et des clés cryptographiques du TEE.
Mettez les deux bout à bout et une application non privilégiée lit à travers, et écrit à travers, la frontière de l’environnement d’exécution de confiance. Ce qu’on a prouvé sur silicium, c’est l’écriture à adresse contrôlée (elle provoque une faute en M-mode : un déni de service fiable). La lecture découle de l’avis publié par Espressif (CVE-2026-45329), et l’exécution de code M-mode nécessite une écriture à valeur contrôlée chaînée par-dessus, pas l’écriture à valeur aléatoire du SID 179 seule. Cadré honnêtement, ça compte quand même.
Écriture confirmée sur matériel réel : ESP32-C6FH4 rev v0.2, ESP-IDF v6.0.1 (la version dans laquelle la régression = a été publiée). La lecture suit l’avis publié, non re-démontrée ici.
SoC affectés : ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2
SID affectés (même classe de contournement) : 179 (aead_encrypt) et 180 (aead_decrypt) sur les quatre SoC, plus 102 (esp_ds_sign) et 103 (esp_ds_start_sign) sur les C5, C6 et H2 (le C61 n’a pas de périphérique DS, ces deux services n’y existent donc pas). L’écriture contrôlée concerne 179/180 et 103 ; le SID 102 injecte un pointeur de paramètre non validé dans le périphérique DS plutôt que d’écrire.
Partie 1 : l’écriture (CVE-2026-45328)
La frontière de confiance
L’ESP-TEE (Trusted Execution Environment) est la couche d’isolation assistée par matériel d’Espressif sur ses SoC RISC-V. L’exécution est scindée en deux mondes :
- TEE : M-mode, privilège supérieur, possède des régions de SRAM sécurisée exclusives, gère les clés et les périphériques crypto.
- REE : le firmware applicatif normal, non privilégié.
Le code REE ne peut pas toucher directement la mémoire du TEE. Il demande au TEE d’agir en son nom via une table de dispatch de services sécurisés : des identifiants de service numérotés (SID) sont associés à des fonctions wrapper. Chaque wrapper est censé valider les arguments pointeurs fournis par le REE, à l’aide de esp_tee_ptr_in_ree(), avant d’appeler le vrai driver du périphérique.
Ces wrappers constituent l’intégralité de la frontière de sécurité. esp_tee_ptr_in_ree() accepte la SRAM non sécurisée, la projection DROM non sécurisée et, lorsqu’elle est prise en charge, la mémoire de données RTC, et rejette toute adresse TEE ou sécurisée, si bien qu’un wrapper qui l’applique à chaque pointeur ne peut jamais être amené à opérer sur la mémoire du TEE. Si un wrapper ignore ou écarte cette vérification, le TEE fait opérer un périphérique sur un pointeur contrôlé par l’attaquant avec le privilège M-mode.
Le TEE est la partie que tout le monde suppose sûre. C’est exactement cette supposition que ce bug transforme en écriture à adresse contrôlée.
Le défaut d’origine
L’avis d’Espressif décrit la cause racine comme une validation de pointeurs incomplète : les wrappers ne vérifiaient que certains des pointeurs fournis par l’appelant avec l’ancien helper esp_tee_ptr_in_ree(), laissant non vérifiés les pointeurs de sortie, les pointeurs à l’intérieur de contextes de structures et les adresses de fin des buffers bornés en longueur, et la vérification de plage sur pointeur nu ne tenait pas compte du dépassement d’espace d’adressage (ptr + len qui repasse par le haut de l’espace d’adressage). La couche de wrappers censée constituer la frontière ne l’appliquait qu’en partie. C’est CVE-2026-45328 telle qu’elle a été publiée en v6.0 et v5.5.4.
Le correctif (v5.5.5, et la ligne v6.0) réécrit la validation : chaque pointeur passe désormais par un nouveau helper sûr vis-à-vis du dépassement, esp_tee_buf_in_ree(), qui rejette une longueur nulle et toute longueur qui déborderait l’adresse de départ, puis vérifie que le début et le dernier octet du buffer sont dans la plage autorisée, et les résultats individuels sont accumulés avec &=.
Le correctif qui n’en était pas un : un caractère
C’est là que ça devient intéressant. Lors du portage de ce correctif sur la branche release/v6.0, un des commits a été oublié dans la version v6.0.1. Toute la régression tient en un seul caractère. Dans components/esp_tee/subproject/main/core/esp_secure_services_iram.c, à l’intérieur de _ss_esp_tee_sec_storage_aead_encrypt() (SID 179), la vérification des données authentifiées supplémentaires est publiée avec un simple = au lieu de &= :
// CORRECTIF INCOMPLET, ESP-IDF v6.0.1 (un commit du correctif a été oublié lors du portage sur release/v6.0)
bool valid_addr = (esp_tee_buf_in_ree(ctx, sizeof(esp_tee_sec_storage_aead_ctx_t)) &&
esp_tee_buf_in_ree(ctx->input, ctx->input_len) &&
esp_tee_buf_in_ree(iv, iv_len) &&
esp_tee_buf_in_ree(tag, tag_len) &&
esp_tee_buf_in_ree(output, ctx->input_len));
if (ctx->aad_len != 0) {
valid_addr = esp_tee_buf_in_ree(ctx->aad, ctx->aad_len); // BUG: '=' should be '&='
}
if (!valid_addr) { return ESP_ERR_INVALID_ARG; }
ESP_FAULT_ASSERT(valid_addr);
return esp_tee_sec_storage_aead_encrypt(ctx, iv, iv_len, tag, tag_len, output);La chaîne à cinq termes valide correctement chaque pointeur, ctx, input, iv, tag, output, via le nouveau helper esp_tee_buf_in_ree() sûr vis-à-vis du dépassement, et stocke le résultat dans valid_addr. Ensuite, si l’appelant a fourni des données authentifiées supplémentaires (aad_len != 0), le bloc conditionnel écrase valid_addr avec un simple = au lieu d’accumuler avec &=. Les cinq vérifications précédentes sont jetées. Un appelant REE qui passe un buffer aad valide et non sécurisé obtient désormais valid_addr = true quel que soit l’endroit où pointent iv, tag, output ou input. L’écriture même que le correctif devait fermer est rouverte, dans la version censée la fermer.
À un caractère près. Ce caractère a rouvert un CVSS 9.3 critique, à l’intérieur même du correctif.
Cette régression n’existe qu’en v6.0.1. La v6.0 et la v5.5.4 utilisent &= (leur faiblesse est l’ancienne vérification esp_tee_ptr_in_ree() sujette au dépassement, le défaut d’origine ci-dessus) ; la v6.0.2 et la v5.5.5 utilisent &= avec le helper sûr. Le même = apparaît dans le wrapper de déchiffrement jumeau (SID 180). On l’a trouvé en relisant le correctif sur les différentes branches, on l’a signalé, et Espressif l’a confirmé, corrigeant l’avis GHSA-mmgp-73p4-92xp pour marquer la v6.0.1 comme affectée et corrigée en v6.0.2, le tout suivi sous la même CVE-2026-45328.
Du contournement à l’écriture à adresse contrôlée
Contourner la vérification n’est que la moitié d’une vulnérabilité. Cela devient une primitive d’écriture à cause de ce que le wrapper appelle ensuite. Le wrapper de chiffrement n’est qu’un passe-plat d’une ligne vers tee_sec_storage_crypt_common() dans tee_sec_storage.c, et c’est là que l’iv non vérifié est utilisé : après la recherche et l’import de la clé, et avant l’exécution du corps AEAD, il est passé directement à esp_fill_random() (ligne 689) :
esp_fill_random(iv, iv_len); // runs before the AEAD body (from source audit)
Le TEE randomise l’IV avant d’exécuter le corps de l’AEAD, donc rien dans le texte chiffré n’a besoin d’être aligné au préalable. Quand iv pointe vers la mémoire M-mode du TEE, le TEE écrit iv_len octets à l’adresse choisie par l’attaquant. Notez précisément ce que contrôle l’attaquant : la destination (iv) et la longueur (iv_len), mais pas le contenu, qui est aléatoire. Adresse et longueur contrôlées, valeur non contrôlée. Cette distinction compte pour ce que cette primitive peut et ne peut pas faire, et nous y reviendrons dans la section impact.
Rayon d’action : quatre handlers
Le même motif de dead-store = apparaît dans trois handlers jumeaux qui partagent l’architecture de validation :
| SID | Handler | Vérifications en dead-store | Sink d’écriture | Exploitabilité |
|---|---|---|---|---|
| 179 | aead_encrypt | iv / tag / output / input / ctx | esp_fill_random(iv), aucune barrière eFuse | Confirmé sur matériel |
| 180 | aead_decrypt | iv / tag / output / input / ctx | memcpy vers output (chemin après vérif du tag) | Même faute de frappe ; chemin plus difficile |
| 102 | esp_ds_sign | data (ptr d’entrée) | le DS lit ses paramètres depuis data | Verrouillé : nécessite une eFuse HMAC-DS gravée |
| 103 | esp_ds_start_sign | esp_ds_ctx + data | *esp_ds_ctx = ctx (écrit un ptr du tas TEE) | Verrouillé : nécessite une eFuse HMAC-DS gravée |
Les SID 102 et 103 n’atteignent le chemin de code dangereux qu’après que ets_hmac_calculate_downstream() a renvoyé ETS_OK, ce qui requiert une clé eFuse provisionnée. Sur un appareil de développement qui en est dépourvu, ils renvoient ESP_ERR_HW_CRYPTO_DS_HMAC_FAIL avant l’écriture. Le SID 179 n’a pas ce verrou, ce qui explique pourquoi c’est celui que nous avons prouvé sur silicium.
Preuve sur silicium réel
Le banc :
- Cible : ESP32-C6FH4 rev v0.2 (MAC
98:A3:16:8E:AF:D4) - SDK : ESP-IDF v6.0.1,
CONFIG_SECURE_ENABLE_TEE=y,CONFIG_SECURE_TEE_SEC_STG_MODE_DEVELOPMENT=y - Console :
/dev/ttyACM0(USB-Serial/JTAG)
La preuve est un harnais de contraste. Il effectue deux fois le même appel AEAD-encrypt avec un iv identique visant une adresse TEE, en ne changeant que aad_len. Ce seul écart isole le dead-store comme déclencheur :
#define TEE_DRAM_TARGET 0x40801044UL /* inside TEE/secure SRAM; MUST be rejected */
uint8_t *tee_iv = (uint8_t *)TEE_DRAM_TARGET;
aead_ctx_t ctx = { .key_id = "pwn", .aad = aad, .aad_len = 16,
.input = input, .input_len = 16 };
/* G1: aad_len = 0 -> full && chain runs, TEE pointer rejected */
aead_ctx_t g1 = ctx; g1.aad_len = 0;
r = svc_aead_encrypt(&g1, tee_iv, 16, ree_tag, 16, ree_out);
/* r == 0x102 (ESP_ERR_INVALID_ARG): validation works as intended */
/* G2: aad_len = 16 -> the '=' dead-stores the iv check, gate bypassed */
r = svc_aead_encrypt(&ctx, tee_iv, 16, ree_tag, 16, ree_out);
/* the TEE faults taking an M-mode store aimed at 0x40801044 */Sur le fil, les deux appels se comportent exactement comme le prédit le source :
I (461) TEE-AEAD-POC: gen_key(AES256,"pwn") -> 0x0
I (468) TEE-AEAD-POC: [G1] aad_len=0, iv->TEE 0x40801044 : calling...
I (469) TEE-AEAD-POC: [G1] ret=0x102 (EXPECT 0x102 => validation works)
I (473) TEE-AEAD-POC: [G2] aad_len=16, iv->TEE 0x40801044 : gate BYPASS + write-fault...
Guru Meditation Error: Core 0 panic'ed (Store access fault). Exception was unhandled.
Fault addr: 0x40030d1e | Origin: M-mode
MEPC : 0x40030d1e RA : 0x4080640c
S1 : 0x40801044 A0 : 0x40801044 A3 : 0x40801048
MSTATUS : 0x00001891 MTVEC : 0x40800001
MCAUSE : 0x00000007 MTVAL : 0x40801044
Rebooting...G1 renvoie 0x102 : avec aad_len = 0 la validation s’exécute et l’adresse TEE est rejetée. G2, le seul changement étant aad_len = 16, contourne la vérification et le TEE plante. Les registres nomment précisément le coupable : MCAUSE = 0x7 (Store/AMO access fault), MTVAL = 0x40801044 (exactement l’iv fourni par l’attaquant, la cible du store), et MSTATUS.MPP = 0b11, donc l’exception a été prise à l’intérieur du TEE au privilège M-mode. Une étiquette à lire attentivement : le gestionnaire de panic affiche l’instruction fautive comme Fault addr (0x40030d1e, égale à MEPC) ; l’adresse de donnée fautive est MTVAL. Ce que cela prouve, c’est le contournement de la frontière : une application non privilégiée a dirigé un store M-mode vers une adresse de son choix, et la vérification de plage qui aurait dû le rejeter ne s’est jamais exécutée. Le store plante ici parce que cette cible est protégée par PMP, ce qui explique aussi pourquoi la même primitive constitue un déni de service fiable.
Une frontière de sécurité matérielle, et une application non privilégiée vient de diriger un store M-mode vers une adresse de son choix. La vérification qui aurait dû l’arrêter a été jetée une ligne plus tôt.
Impact : ce que vous rapporte une écriture dans le TEE
Soyons d’abord précis sur la primitive. Via le SID 179, l’attaquant contrôle l’adresse et la longueur de l’écriture, mais les octets sont aléatoires. Cela donne déjà deux choses directement, et ouvre la voie à davantage une fois qu’une écriture à valeur contrôlée est chaînée.
Directement, à partir de l’écriture à valeur aléatoire du SID 179 :
- Contournement de la frontière. Une application REE non privilégiée fait émettre au TEE un store M-mode vers n’importe quelle adresse de son choix. L’isolation pour laquelle le TEE existe ne tient plus.
- DoS fiable sur les appareils OT/ICS. Visez l’écriture vers la SRAM TEE protégée et le store M-mode plante en une panique irrécupérable. Un seul appel de service fait planter la cible en une panique M-mode suivie d’un redémarrage, trivialement transformable en boucle de déni de service persistant, ce qui compte pour les équipements industriels critiques pour la sécurité. Aucune adresse cible précise n’est nécessaire ; la seule condition préalable est une clé AES256 utilisable en stockage sécurisé, que l’appelant peut provisionner lui-même en mode développement. On l’a prouvé sur ESP32-C6 ; les C5, C61 et H2 partagent le même code de wrapper et les mêmes entrées de service SID 179/180.
Avec un chemin d’écriture à valeur contrôlée (par exemple le pointeur output du SID 180, aead_decrypt) :
- Divulgation de clés et de secrets. Corrompez le pointeur
outputd’un appel de déchiffrement pour que le TEE écrive des données déchiffrées ou du matériel de clé dans une mémoire lisible par le REE. Combinée à la lecture de la Partie 2, c’est l’extraction directe des secrets que le TEE est censé protéger. - Escalade vers l’exécution de code M-mode. Une écriture à valeur choisie dans un pointeur de fonction de dispatch ou d’interruption du TEE redirige le prochain appel de service vers le code de l’attaquant au privilège le plus élevé de la puce. De là, le contrôleur de flash est accessible (un implant persistant survivant au redémarrage et à l’OTA) et l’état de vérification du Secure Boot est corruptible. Cela découle d’une écriture à valeur contrôlée, pas de l’écriture à valeur aléatoire du SID 179 à elle seule.
Le correctif
Le correctif d’Espressif réécrit la validation plutôt que de rapiécer une seule ligne. Selon l’avis, les wrappers font désormais passer chaque argument pointeur par un nouveau helper sûr vis-à-vis du dépassement, esp_tee_buf_in_ree(), qui vérifie que l’étendue complète de chaque buffer (début et fin) est dans la plage autorisée, au lieu d’un simple pointeur. Cela ferme à la fois les cas de pointeurs non vérifiés et le dépassement d’espace d’adressage que les anciennes vérifications esp_tee_ptr_in_ree() manquaient. Le correctif complet est publié en v5.5.5 et v6.0.2 ; la v6.0.1 a reçu la réécriture du helper mais pas le commit qui rétablit l’accumulation &= sur la vérification aad de l’AEAD, ce qui est la régression documentée plus haut.
Pour le dead-store spécifique montré plus haut, le défaut local est exactement d’un caractère, le = qui devrait accumuler :
// esp_secure_services_iram.c, SID 179 (encrypt) / 180 (decrypt)
if (ctx->aad_len != 0) {
valid_addr &= esp_tee_buf_in_ree(ctx->aad, ctx->aad_len); // was '='
}
// esp_secure_services.c, SID 102 (le 103 est analogue, avec en plus une vérification de *esp_ds_ctx) :
// on sort dès la première vérification, puis on accumule,
// ainsi rien ne peut être mis en dead-store ensuite
bool valid_addr = esp_tee_buf_in_ree(data, sizeof(esp_ds_data_t));
if (!valid_addr) { return ESP_ERR_INVALID_ARG; }
size_t n = get_ds_msg_sign_len(data->rsa_length);
valid_addr &= (n > 0) && esp_tee_buf_in_ree(message, n) && esp_tee_buf_in_ree(signature, n);La leçon plus large, c’est le motif : une validation par service étalée sur plusieurs instructions et accumulée à la main est à une faute de frappe d’être abandonnée. La replier dans un unique helper qui renvoie un bool, consommé immédiatement sous la forme if (!ok) return ESP_ERR_INVALID_ARG;, supprime le mode de défaillance. Des tests unitaires appelant chaque service avec chaque pointeur, un à la fois, pointé vers la mémoire du TEE et exigeant le rejet, auraient détecté chaque cas.
Partie 2 : la lecture (CVE-2026-45329)
L’image miroir
L’écriture n’est qu’une moitié de l’histoire. La même couche de wrappers a une seconde faille, plus discrète, pointant dans l’autre direction.
Là où le chemin de chiffrement met en dead-store une vérification qu’il a exécutée, plusieurs wrappers jumeaux ne valident jamais leurs pointeurs d’entrée du tout. Ils vérifient où va la sortie, mais pas d’où vient l’entrée. Ainsi un appelant REE peut remettre à un wrapper un pointeur d’entrée visé droit vers la mémoire exclusive au TEE. Le wrapper le passe à un périphérique crypto/stockage matériel (ECC, SHA, ou le chemin SPI/flash) tournant en M-mode. Le périphérique lit depuis l’adresse TEE choisie par l’attaquant et renvoie sa sortie au REE :
/* Illustrative: the read pattern (CVE-2026-45329), not a runnable PoC.
* The wrapper validates the output pointer but never the input pointer. */
uint8_t *tee_secret = (uint8_t *)0x40801000; /* TEE-exclusive SRAM */
uint8_t digest[32]; /* REE-readable buffer */
/* A hash/crypto service whose input pointer is left unchecked:
* input aimed at TEE memory, output back into the REE. */
esp_tee_service_call(/* argc */, /* SHA service id */,
(uint32_t)tee_secret, /* input -> TEE memory (unchecked) */
(uint32_t)sizeof(digest),
(uint32_t)digest); /* output -> REE (checked) */
/* digest now holds a hash of TEE-resident bytes, computed in M-mode and
* handed back to the REE. With a hash service this is a byte-wise oracle:
* aim the input at one address with len 1 and brute-force each byte offline
* (256 candidates per position). Sibling services whose peripheral returns
* the input-derived bytes more directly (not a digest) leak them outright. */Pointez une entrée de hash ou de crypto vers la SRAM sécurisée du TEE et le périphérique M-mode la lit pour vous : avec un service de digest, vous récupérez les octets via un oracle de hash, une position à la fois ; avec un service qui renvoie directement sa sortie dérivée de l’entrée, vous les lisez tout droit. Aucune exception, aucun crash, aucune trace.
C’est une lecture hors limites au travers de la frontière TEE/REE (CWE-125, avec divulgation d’information CWE-200) : du code TEE, des données TEE et les clés cryptographiques que toute l’isolation existe pour protéger. La portée est Changed, la confidentialité High, et cela ne nécessite aucun privilège TEE (CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N).
Associez-la à l’écriture de la Partie 1 et la frontière disparaît dans les deux directions : lire les clés, puis écrire pour corrompre ce qu’il reste.
Le correctif (lecture)
La lecture est l’image miroir de l’écriture, et son correctif l’est aussi. Ces wrappers étaient entièrement dépourvus de vérifications sur les pointeurs d’entrée, donc le correctif ajoute la validation esp_tee_buf_in_ree() sur les pointeurs d’entrée qui n’étaient jamais vérifiés au départ. Le même helper, appliqué aux arguments que le chemin de chiffrement se contentait de mettre en dead-store.
Chronologie
| Date | Événement |
|---|---|
| Mai 2026 | Les deux failles signalées à Espressif PSIRT |
| 2026-05-13 | Avis de lecture publié, GHSA-w82j-7q63-7pqm (CVE-2026-45329) |
| 2026-06-03 | Avis d’écriture publié, GHSA-mmgp-73p4-92xp (CVE-2026-45328) ; l’avis annonce le correctif en v5.5.5 et v6.0.1 |
| Août 2026 | En relisant le correctif sur les différentes branches, découverte de l’écriture rouverte en v6.0.1 (la régression =) ; confirmée sur matériel (ESP32-C6, v6.0.1) et signalée à Espressif |
| Août 2026 | Espressif confirme qu’un commit du correctif a été oublié dans la version v6.0.1 ; l’avis GHSA-mmgp-73p4-92xp est corrigé, la v6.0.1 est marquée affectée et corrigée en v6.0.2 |
Versions affectées
SoC affectés : ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2 (toutes les cibles RISC-V compatibles TEE).
| Version | Lecture (CVE-2026-45329) | Écriture (CVE-2026-45328) |
|---|---|---|
| < v5.5.0 | non affectée (composant absent) | non affectée |
| v5.5.0 à v5.5.3 | non affectée (antérieure au défaut) | non affectée |
| v5.5.4 | affectée | affectée |
| v6.0 | affectée | affectée (vérification d’origine sujette au dépassement) |
| v6.0.1 | corrigée | toujours affectée (le correctif incomplet =) |
| v5.5.5 | corrigée | corrigée |
| v6.0.2 | corrigée | corrigée |
La nuance porte sur la ligne v6.0 : la lecture est corrigée en v6.0.1, mais l’écriture n’est complètement corrigée qu’en v6.0.2, car il manquait à la v6.0.1 l’un des commits du correctif de l’écriture. Cibles de mise à jour : sur la ligne 5.5, passez en v5.5.5 ; sur la ligne 6.0, passez en v6.0.2.
Avis : GHSA-mmgp-73p4-92xp pour l’écriture (CVE-2026-45328), et GHSA-w82j-7q63-7pqm pour la lecture (CVE-2026-45329).
Références
- GHSA-mmgp-73p4-92xp, avis Espressif pour l’écriture (CVE-2026-45328)
- GHSA-w82j-7q63-7pqm, avis Espressif pour la lecture (CVE-2026-45329)
components/esp_tee/subproject/main/core/esp_secure_services_iram.cetesp_secure_services.c, wrappers vulnérablescomponents/esp_tee/subproject/components/tee_sec_storage/tee_sec_storage.c, sink d’écriture- Espressif ESP32-C6 Technical Reference Manual, modèle de privilèges RISC-V, plan mémoire M-mode
