CVE-2026-15890 Overview
CVE-2026-15890 is a race condition in the Zephyr RTOS Platform Security Architecture (PSA) Internal Trusted Storage (ITS) transform module. The default AEAD nonce provider, secure_storage_its_transform_aead_get_nonce() in subsys/secure_storage/src/its/transform/aead_get.c, stores its nonce counter in unsynchronized function-local static variables. Concurrent threads writing the same ITS UID can receive identical nonces, breaking AES-GCM and ChaCha20-Poly1305 confidentiality and integrity guarantees. The flaw is classified under [CWE-323: Reusing a Nonce, Key Pair in Encryption].
Critical Impact
Nonce reuse under a shared AEAD key leaks the XOR of plaintexts, and for AES-GCM exposes the authentication key, enabling forgery of stored secrets including PSA persistent keys.
Affected Products
- Zephyr RTOS subsys/secure_storage component
- ITS back-end zms.c (log-structured flash store)
- ITS settings/NVS back-end via settings.c
Discovery Timeline
- 2026-09-21 - CVE-2026-15890 published to NVD
- 2026-09-22 - Last updated in NVD database
Technical Details for CVE-2026-15890
Vulnerability Analysis
The default nonce provider maintains two function-local statics, s_nonce and s_nonce_initialized, without any locking. Every ITS write reaches the provider through secure_storage_its_transform_to_store() to obtain a fresh nonce. When two threads invoke the provider concurrently, both the initialization path calling psa_generate_random() followed by memcpy() and the non-atomic increment-then-copy path can hand the same counter value to two distinct encryption operations.
The ITS layer, specifically secure_storage_its_set() in subsys/secure_storage/src/its/implementation.c, performs no serialization of its own. Concurrent same-UID writes therefore reach the racy provider directly. Because the AEAD key is derived per entry UID, the security-relevant collision is two concurrent writes to the same UID both receiving the identical nonce.
Both shipped back-ends are log-structured flash stores with deferred garbage collection. A superseded entry remains physically present in the partition until its sector is reclaimed, so both ciphertexts stay readable in the raw image. An adversary able to read the raw backing storage can then exploit the nonce reuse.
Root Cause
The provider lacked a synchronization primitive around shared mutable state. The built-in key providers (DEVICE_ID_HASH and ENTRY_UID_HASH) salt derived keys with the entry UID, which limits the exposure to same-UID concurrent writes rather than cross-UID collisions.
Attack Vector
Exploitation requires local access, an application that writes the same ITS UID concurrently from two threads, and the ability to read raw flash storage. The attack complexity is high because the timing window is narrow and requires a specific application usage pattern.
#include <zephyr/secure_storage/its/transform/aead_get.h>
#include <zephyr/drivers/hwinfo.h>
#include <zephyr/init.h>
+#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <psa/crypto.h>
#include <string.h>
Source: Zephyr GitHub Commit dc66397. The fix serializes the provider with K_MUTEX_DEFINE(s_nonce_mutex) held for the duration of nonce generation.
Detection Methods for CVE-2026-15890
Indicators of Compromise
- Duplicate ciphertext blocks present in raw ITS partition dumps under the same derived key.
- Multiple ITS entries with matching UIDs but distinct ciphertexts remaining in log-structured flash before garbage collection.
- Application call graphs showing concurrent psa_its_set() invocations on the same UID from multiple threads.
Detection Strategies
- Perform static analysis of application source to identify code paths invoking secure_storage_its_set() on identical UIDs from separate threads or ISR contexts.
- Instrument the ITS provider during test builds to log nonce values and flag any repetition per (UID, key) pair.
- Inspect raw flash images from field devices and compare AEAD nonces across stale and current entries for the same UID.
Monitoring Recommendations
- Track firmware versions across fleets and confirm that deployed images incorporate the mutex-protected nonce provider.
- Monitor build pipelines for the presence of the K_MUTEX_DEFINE(s_nonce_mutex) symbol in aead_get.c.
- Review threading models in secure storage consumers during code review to eliminate concurrent same-UID writes.
How to Mitigate CVE-2026-15890
Immediate Actions Required
- Apply the upstream Zephyr patch that serializes secure_storage_its_transform_aead_get_nonce() with K_MUTEX_DEFINE(s_nonce_mutex).
- Audit application code for concurrent writes to the same ITS UID and refactor to serialize such operations at the application layer as an interim measure.
- Rotate PSA persistent keys and secrets stored via ITS on devices where concurrent same-UID writes may have occurred.
Patch Information
The upstream fix is available in Zephyr GitHub Commit dc66397. Additional details are documented in GitHub Security Advisory GHSA-23jw-7xv2-xr28.
Workarounds
- Wrap all psa_its_set() calls that may target overlapping UIDs in an application-level mutex until firmware can be updated.
- Restrict ITS writes for a given UID to a single dedicated thread.
- Enable garbage collection or sector reclamation policies that minimize the window during which stale ciphertexts remain in flash, reducing exploitability.
# Apply the upstream fix in a Zephyr west workspace
cd zephyrproject/zephyr
git fetch origin
git cherry-pick dc66397309248271df1fd0131d68ce8ea62bf91b
west build -b <board> <application>
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.