IT Security 3 weeks ago

CVE-2026-19577: Zephyr RTOS IPv6 Routing Out-of-Bounds Read – Impact, Exploits & Mitigation

CVE-2026-19577 is a high‑severity out‑of‑bounds read in Zephyr RTOS’s IPv6 routing code that lets an attacker on the same LAN trigger a kernel panic or leak up to 8 bytes of RAM. The guide explains the flaw, attack scenarios, detection methods, and step‑by‑step remediation. CVE-2026-19577 is a high‑severity out‑of‑bounds read in Zephyr RTOS’s IPv6 routing code that lets an attacker on the same LAN trigger a kernel panic or leak up to…

IT Security

CVE-2026-19577: Out-of-Bounds Read in Zephyr RTOS IPv6 Routing

Executive Summary

CVE-2026-19577 is a high-severity out-of-bounds (OOB) read vulnerability affecting Zephyr RTOS IPv6 routing subsystem. An attacker on the local network link can trigger a kernel panic in debug builds or leak up to 8 bytes of static RAM in production environments. The vulnerability requires adjacent network access but no authentication or special configuration.

CVSS v3.1 Score: 7.1 (High)
Attack Vector: Adjacent Network (Layer 2)
Primary Impact: Denial of Service & Memory Disclosure


What Is CVE-2026-19577?

Vulnerability Overview

CVE-2026-19577 resides in the net_route_ipv6_packet() function within Zephyr RTOS’s IPv6 routing subsystem (subsys/net/ip/route_ipv6.c). The vulnerability occurs when the code attempts to retrieve a link-layer address for an unresolved IPv6 neighbor cache entry without proper validation.

The core issue: when a neighbor cache entry remains in an INCOMPLETE state (unresolved), the code assigns an invalid index value (NET_NBR_LLADDR_UNKNOWN = 0xFF). Subsequent calls to net_nbr_get_lladdr() calculate a pointer approximately 2.5 KB beyond the valid array boundary. Because this pointer is non-NULL, downstream NULL checks fail to catch the error.

Two distinct impacts emerge:

  • Debug builds (CONFIG_ASSERT=y): Kernel assertion fires immediately, causing system panic
  • Production builds (assertions disabled): Leaked memory bytes are embedded in outgoing network frames

Affected Systems and Versions

Component Details
Product Zephyr Real-Time Operating System (RTOS)
Subsystem Network Stack / IPv6 Routing
Affected Versions All versions with vulnerable code pattern in route_ipv6.c and nbr.c when CONFIG_NET_IPV6_ROUTE is enabled
Default Status Enabled by default when IPv6 neighbor caching is active

Why This Matters for Your Deployment

Zephyr RTOS powers embedded IoT devices, industrial controllers, and edge computing platforms. This vulnerability affects:

  • Default configurations: No special routing setup required—vulnerability exists in standard builds
  • Wide attack surface: Any device on the same local network can exploit this
  • Silent data leakage: Production systems leak memory without obvious indicators
  • Service disruption: Debug builds crash repeatedly under attack

Organizations deploying Zephyr-based devices in shared network environments face immediate risk.


How the Vulnerability Works

Root Cause in the Code

The vulnerability stems from a missing validation check in the IPv6 routing path:

// Vulnerable code flow in net_route_ipv6_packet()
struct net_nbr *nbr = net_route_ipv6_get_info(...);
// No check for nbr->idx == NET_NBR_LLADDR_UNKNOWN (0xFF)
struct net_linkaddr *lladdr = net_nbr_get_lladdr(nbr->idx);
// This NULL check passes because pointer is non-NULL (but out-of-bounds)
if (lladdr == NULL) {
    return -EINVAL;  // Never reached
}
// Proceeds with invalid memory reference
memcpy(dest_addr, lladdr->addr, lladdr->len);

The net_nbr_get_lladdr() function in subsys/net/ip/nbr.c performs a simple array offset calculation without bounds validation:

// Inside net_nbr_get_lladdr()
return &net_neighbor_lladdr[idx];  // No bounds check on idx

When idx = 255 (0xFF), this returns a pointer far beyond the allocated array.

Memory Layout and Out-of-Bounds Access

Assuming default configuration (CONFIG_NET_IPV6_MAX_NEIGHBORS = 8):

Memory Layout:
┌─────────────────────────────────────────────────────────────┐
│ net_neighbor_lladdr[0..7]  │  Unrelated Static RAM  │ [OOB] │
│ (Valid: 64 bytes)          │  (~2.5 KB)             │ Access│
└─────────────────────────────────────────────────────────────┘
 ↑                                                      ↑
 Valid array                                            Index 255 pointer
 (indices 0-7)                                          (~2.5 KB past end)

The calculation: &net_neighbor_lladdr[255] produces a valid pointer address pointing to unallocated memory containing adjacent static data structures.

Why NULL Checks Fail

Standard NULL pointer validation cannot catch this error because:

  1. Pointer is non-NULL: The calculated address is a valid memory location (just not intended for this array)
  2. No runtime bounds checking: The function lacks index range validation
  3. Macro-only protection: NET_ASSERT macros are disabled in production builds
  4. Assumption of validity: Downstream code assumes any non-NULL pointer is safe

Attack Scenarios You Need to Know

Scenario A: Denial of Service (Assert-Enabled Builds)

Prerequisites:

  • Target compiled with CONFIG_ASSERT=y (common in development/debug builds)
  • Attacker has Layer 2 access to target’s network segment

Attack Steps:

  1. Create unresolved neighbor entry: Send IPv6 Router Advertisement (RA) lacking Source Link-Layer Address option, or trigger Neighbor Solicitation to non-existent address
  2. Trigger routing: Send unicast IPv6 packet destined for the unresolved neighbor
  3. Kernel panic: net_route_ipv6_packet() calls net_nbr_get_lladdr(0xFF), assertion fires, system crashes

Impact: Repeatable remote denial of service—attacker can crash device repeatedly with minimal packet overhead

Real-world scenario: Industrial IoT device on shared factory network receives malicious IPv6 packets, crashes repeatedly, disrupting production monitoring

Scenario B: Memory Disclosure (Production Builds)

Prerequisites:

  • Target compiled with assertions disabled (typical production configuration)
  • Attacker has Layer 2 access
  • Passive network listener present (or attacker captures own traffic)

Attack Steps:

  1. Create unresolved neighbor entry: Same method as Scenario A
  2. Send trigger packet: Unicast IPv6 packet to unresolved neighbor
  3. Memory leak: Code reads from &net_neighbor_lladdr[255], interprets adjacent static RAM as valid struct net_linkaddr
  4. Exfiltration: If the len field at that memory location passes validation, up to 8 bytes are copied into outgoing Ethernet frame’s destination address
  5. Broadcast: Frame transmitted on local network, exposing leaked data to any L2 listener

Impact: Incremental memory disclosure—attacker learns 8 bytes per malicious packet, can target specific memory regions through repeated attacks

Real-world scenario: Attacker on corporate network segment leaks cryptographic keys, session tokens, or configuration data from embedded device’s static RAM

Attack Prerequisites and Feasibility

Requirement Feasibility Notes
Layer 2 access High Must be on same network segment; no Internet routing required
Authentication None Unauthenticated attack
Special config None Works on default builds
Packet crafting Low Standard IPv6 Neighbor Discovery messages
Detection difficulty High Appears as normal IPv6 traffic

Exploitability Rating: HIGH

No specialized tools or deep networking knowledge required. Standard IPv6 utilities can craft necessary packets.


Severity and Risk Assessment

CVSS v3.1 Score Breakdown

CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:H
Metric Value Justification
Attack Vector (AV) Adjacent (A) Requires Layer 2 network access; no Internet routing
Attack Complexity (AC) Low (L) No special conditions; default configurations vulnerable
Privileges Required (PR) None (N) Unauthenticated attack
User Interaction (UI) None (N) No user action needed
Scope (S) Unchanged (U) Impact limited to vulnerable system
Confidentiality (C) Low (L) Max 8 bytes leaked per packet; limited data exposure
Integrity (I) None (N) Read-only vulnerability; no data modification
Availability (A) High (H) System panic in debug builds; DoS possible

Base Score: 7.1 (HIGH)

Threat Actor Profile

  • Skill Level: Low to Medium
  • Access Requirements: Local network presence
  • Motivation: Service disruption, data exfiltration, reconnaissance
  • Typical Actors: Disgruntled employees, network-adjacent attackers, supply chain adversaries

What This Vulnerability Cannot Do

Important limitations to understand:

  • ❌ No Remote Code Execution: Read-only access at fixed offset; no pointer manipulation
  • ❌ No Out-of-Bounds Write: Cannot modify memory or inject code
  • ❌ No Internet-based exploitation: Requires Layer 2 adjacency
  • ❌ No privilege escalation: Operates within existing process context
  • ❌ No controllable data leak: Attacker cannot choose which bytes are leaked
  • ❌ No authentication bypass: Unrelated to access control systems

Detecting Active Exploitation

Network-Based Detection Indicators

Monitor for these IPv6 traffic patterns:

1. Router Advertisements (ICMPv6 Type 134) lacking Source Link-Layer Address option
   - Unusual RA frequency from single source
   - RAs with router lifetime but no link-layer info
2. Neighbor Solicitations (ICMPv6 Type 135) to non-existent addresses
   - NS queries for addresses never seen in ARP/NDP before
   - Rapid NS bursts followed by unicast traffic to same targets
3. Unicast IPv6 packets to unresolved neighbors
   - Traffic to addresses in "incomplete" state
   - Packets arriving immediately after NS without ND reply

Detection rule example (Suricata/Snort):

alert ipv6 any any -> any any (msg:"CVE-2026-19577 Exploitation Attempt"; 
  icmpv6_type:134; content:"|3a|"; distance:0; within:1; 
  sid:1000001; rev:1;)

Static Code Analysis Patterns

Search your codebase for vulnerable patterns:

# Find unchecked net_nbr_get_lladdr() calls
grep -n "net_nbr_get_lladdr" subsys/net/ip/*.c | grep -v "NET_NBR_LLADDR_UNKNOWN"
# Identify missing bounds checks
grep -B5 "net_nbr_get_lladdr" subsys/net/ip/route_ipv6.c | grep -v "if.*idx"

Vulnerable code signature:

// Pattern 1: Direct call without validation
struct net_linkaddr *lladdr = net_nbr_get_lladdr(nbr->idx);
// Pattern 2: NULL check only (insufficient)
if (lladdr != NULL) {
    // Process lladdr
}
// Pattern 3: Missing INCOMPLETE check
if (nbr->state == NET_NBR_REACHABLE) {
    // Still vulnerable if idx not checked
}

Log Signals to Monitor

System logs to watch:

  • Kernel assertion failures in net_nbr.c or route_ipv6.c
  • Unexpected system reboots correlated with IPv6 traffic spikes
  • Memory access violations in network stack
  • Repeated kernel panics from same source IP

Application logs:

  • Network interface errors or resets
  • IPv6 routing failures
  • Neighbor cache state anomalies

Fixing the Vulnerability

Code-Level Remediation

Primary fix in subsys/net/ip/route_ipv6.c:

// BEFORE (Vulnerable)
static int net_route_ipv6_packet(struct net_pkt *pkt, ...)
{
    struct net_nbr *nbr = net_route_ipv6_get_info(...);
    struct net_linkaddr *lladdr = net_nbr_get_lladdr(nbr->idx);
    if (lladdr == NULL) {
        return -EINVAL;
    }
    // ... proceed with lladdr
}
// AFTER (Fixed)
static int net_route_ipv6_packet(struct net_pkt *pkt, ...)
{
    struct net_nbr *nbr = net_route_ipv6_get_info(...);
    // Explicit check for unresolved neighbor
    if (nbr->idx == NET_NBR_LLADDR_UNKNOWN) {
        NET_DBG("Neighbor unresolved, cannot route");
        return -EINVAL;
    }
    struct net_linkaddr *lladdr = net_nbr_get_lladdr(nbr->idx);
    if (lladdr == NULL) {
        return -EINVAL;
    }
    // ... proceed with lladdr
}

Secondary fix in subsys/net/ip/nbr.c:

// BEFORE (Vulnerable)
struct net_linkaddr *net_nbr_get_lladdr(uint8_t idx)
{
    return &net_neighbor_lladdr[idx];
}
// AFTER (Fixed with bounds checking)
struct net_linkaddr *net_nbr_get_lladdr(uint8_t idx)
{
    if (idx == NET_NBR_LLADDR_UNKNOWN || 
        idx >= CONFIG_NET_IPV6_MAX_NEIGHBORS) {
        return NULL;
    }
    return &net_neighbor_lladdr[idx];
}

Patching Strategy

Immediate actions:

  1. Identify affected devices: Audit all Zephyr deployments with IPv6 enabled
  2. Prioritize by exposure: Focus on devices with Layer 2 network access
  3. Prepare patches: Apply fixes to your Zephyr fork or wait for official release
  4. Test thoroughly: Validate IPv6 routing functionality after patching

Phased rollout:

Phase 1 (Week 1): Patch development/test environments
Phase 2 (Week 2): Patch staging/pre-production systems
Phase 3 (Week 3-4): Staged production rollout by region/criticality
Phase 4 (Ongoing): Monitor for exploitation attempts

Testing Your Fix

Validation checklist:

# 1. Compile with fix applied
west build -b <board> -d build_fixed
# 2. Unit test: Verify bounds checking
# Add test case for idx == 0xFF
test_net_nbr_get_lladdr_invalid_index()
# 3. Integration test: IPv6 routing with unresolved neighbors
# Send RA without link-layer option, verify graceful handling
# Send unicast to unresolved neighbor, verify packet drop (not crash)
# 4. Regression test: Normal IPv6 routing still works
# Verify standard neighbor resolution and routing functions
# Test with resolved neighbors, verify no performance impact
# 5. Stress test: Rapid neighbor state changes
# Simulate high-frequency ND messages
# Verify no memory leaks or crashes

Test code example:

void test_cve_2026_19577_fix(void)
{
    // Create unresolved neighbor entry
    struct net_nbr *nbr = net_nbr_get_unused();
    nbr->idx = NET_NBR_LLADDR_UNKNOWN;
    // Attempt to get link-layer address
    struct net_linkaddr *lladdr = net_nbr_get_lladdr(nbr->idx);
    // Verify fix: should return NULL, not out-of-bounds pointer
    zassert_is_null(lladdr, "Expected NULL for invalid index");
}

Immediate Workarounds

Network Defense Measures

While awaiting patches, implement these controls:

1. IPv6 Router Advertisement Guard (RA Guard)

Deploy on managed switches to block untrusted RAs:

[Cisco IOS Example]
ipv6 nd raguard policy STRICT
  device-role host
  router-preference ignore
  ra-guard enable
!
interface GigabitEthernet0/1
  ipv6 nd raguard attach-policy STRICT

Effect: Prevents attacker from creating unresolved neighbor entries via spoofed RAs

2. VLAN Segmentation

Isolate Zephyr devices on dedicated VLANs:

[Network Design]
- IoT Devices VLAN: 100 (isolated)
- Management VLAN: 200 (restricted access)
- Production VLAN: 300 (no untrusted devices)
Access Control:
- Block inter-VLAN IPv6 traffic except where necessary
- Monitor VLAN 100 for suspicious ND activity

Effect: Limits attacker’s ability to reach vulnerable devices

3. Private VLAN (PVLAN) Implementation

[Cisco Catalyst Example]
vlan 100
  private-vlan community
vlan 101
  private-vlan isolated
vlan 102
  private-vlan primary
  private-vlan association 100,101
interface GigabitEthernet0/1
  switchport private-vlan host-association 102 100

Effect: Prevents device-to-device communication on same segment

Configuration Hardening

Disable IPv6 routing if not required:

// In prj.conf
CONFIG_NET_IPV6_ROUTE=n

Restrict neighbor cache size:

// In prj.conf
CONFIG_NET_IPV6_MAX_NEIGHBORS=4  # Reduce from default 8

Enable IPv6 address filtering:

// In application code
// Only accept packets from known IPv6 addresses
struct in6_addr allowed_peers[] = {
    // List of trusted IPv6 addresses
};

Disable IPv6 if not needed:

// In prj.conf
CONFIG_NET_IPV6=n
CONFIG_NET_IPV4=y  # Use IPv4 only if feasible

Temporary Mitigation While Patching

Short-term protective measures:

Mitigation Effectiveness Complexity
RA Guard High Medium
VLAN isolation High Medium
Network monitoring Medium Low
Disable IPv6 Very High Low
Reduce neighbor cache Medium Low

Recommended interim approach:

  1. Immediate (Day 1): Enable RA Guard on network switches
  2. Short-term (Week 1): Implement VLAN segmentation
  3. Medium-term (Week 2): Deploy network monitoring for ND anomalies
  4. Long-term (Week 3+): Apply code patches and redeploy

FAQ

Can this vulnerability be exploited over the Internet?

No. CVE-2026-19577 requires adjacent network access (Layer 2). The attacker must be able to send raw IPv6 Neighbor Discovery messages directly to the target device on the same network segment. Internet-based exploitation is not possible because:

  • IPv6 ND messages don’t traverse routers
  • Requires direct Ethernet/link-layer frame transmission
  • No DNS or application-layer attack vector exists

Implication: Devices on isolated networks or behind properly configured firewalls have reduced risk, but internal network threats remain significant.

Does this enable remote code execution?

No. This is strictly a read-only vulnerability. The out-of-bounds access is limited to reading memory at a fixed offset (index 255). There is:

  • No out-of-bounds write capability
  • No pointer manipulation or corruption
  • No stack overflow or heap spray
  • No direct path to arbitrary code execution

However: In theory, if leaked memory contains function pointers or other sensitive data, an attacker could potentially chain this with other vulnerabilities. Treat as part of a multi-stage attack, not a standalone RCE.

Why do NULL pointer checks not catch this?

The vulnerability bypasses NULL checks because net_nbr_get_lladdr() returns a valid, non-NULL pointer—just one pointing to unintended memory:

// Index 255 calculation:
&net_neighbor_lladdr[255]  // Valid address, wrong location
                           // ~2.5 KB past array end
                           // Points to adjacent static RAM
// NULL check passes:
if (lladdr == NULL) {  // FALSE - pointer is not NULL
    return -EINVAL;    // Never executed
}

Why this matters: Standard defensive programming (NULL checks) is insufficient. Bounds validation is required.

Do I need special routing configuration to be vulnerable?

No. CONFIG_NET_IPV6_ROUTE is enabled by default whenever IPv6 neighbor caching is active in Zephyr RTOS. Most standard networking builds are vulnerable without any special setup:

// Default Zephyr configuration
CONFIG_NET_IPV6=y              // Enabled by default
CONFIG_NET_IPV6_NBR_CACHE=y    // Enabled by default
CONFIG_NET_IPV6_ROUTE=y        // Enabled by default

Implication: You’re likely vulnerable unless you explicitly disabled IPv6 routing in your build configuration.

What’s the difference between debug and production impact?

Build Type Configuration Impact Severity
Debug CONFIG_ASSERT=y Kernel panic on trigger Critical (DoS)
Production CONFIG_ASSERT=n Memory leak (8 bytes/packet) High (data exposure)

Debug builds: Crash immediately when vulnerability triggered—obvious but disruptive

Production builds: Silent memory leakage—harder to detect but enables data exfiltration

Recommendation: Even production builds should be patched; don’t rely on assertions being disabled for security.

How much data can be leaked?

Maximum 8 bytes per malicious packet. The leak is constrained by:

  1. Fixed offset: Always reads from index 255 (~2.5 KB past array)
  2. Structure size: struct net_linkaddr contains 8-byte address field
  3. Length validation: Code checks len <= NET_LINK_ADDR_MAX_LENGTH (typically 6-8 bytes)
  4. Single read: One packet = one leak operation

Cumulative risk: Attacker can send multiple packets to leak different memory regions incrementally. Over time, significant data exposure is possible.

Example: 100 packets = 800 bytes of leaked memory

Can I disable IPv6 routing to avoid this?

Yes, but with caveats. You can disable IPv6 routing:

// In prj.conf
CONFIG_NET_IPV6_ROUTE=n

However:

  • This disables routing functionality—may break legitimate use cases
  • Other IPv6 vulnerabilities may still exist
  • Not a permanent solution; patching is still required
  • Reduces functionality unnecessarily

Better approach: Apply the code patch rather than disabling features.

What Zephyr versions are affected?

All versions with the vulnerable code pattern in route_ipv6.c and nbr.c where CONFIG_NET_IPV6_ROUTE is enabled alongside the IPv6 neighbor cache.

Specific affected versions:

  • Zephyr 2.7.x through 3.x (confirmed)
  • Likely earlier versions (2.6.x and prior)
  • Any custom Zephyr fork with IPv6 networking

Check your version:

west --version
# or
cat VERSION

Recommendation: Assume your version is affected unless explicitly patched. Check Zephyr security advisories for official patch releases.


References

Official Sources

  • CVE Identifier: CVE-2026-19577
  • Zephyr Project: https://www.zephyrproject.org/
  • Zephyr Security: https://docs.zephyrproject.org/latest/security/

Affected Code Files

  • subsys/net/ip/route_ipv6.c — IPv6 routing logic
  • subsys/net/ip/nbr.c — Neighbor cache management
  • subsys/net/ip/ipv6.c — IPv6 packet processing

Related Standards

  • RFC 4861 — Neighbor Discovery for IPv6
  • RFC 4862 — IPv6 Stateless Address Autoconfiguration
  • RFC 6775 — IPv6 Neighbor Discovery Extensions for Low-Power and Lossy Networks

Detection Tools

  • Wireshark: IPv6 protocol analysis and ND packet inspection
  • tcpdump: Capture suspicious IPv6 traffic patterns
  • Suricata/Snort: Network-based intrusion detection

Key Takeaways

✅ Immediate Actions:

  1. Audit all Zephyr deployments for IPv6 enablement
  2. Implement RA Guard on network switches
  3. Segment IoT devices into isolated VLANs
  4. Monitor for suspicious IPv6 Neighbor Discovery traffic

✅ Short-term (1-2 weeks):

  1. Apply code patches to development builds
  2. Test thoroughly in staging environments
  3. Deploy network monitoring for exploitation attempts

✅ Long-term (2-4 weeks):

  1. Roll out patched firmware to production devices
  2. Maintain network segmentation and monitoring
  3. Subscribe to Zephyr security advisories

Remember: This vulnerability requires local network access but no authentication. Treat it seriously in any environment where untrusted devices share network segments with your Zephyr deployments.

Memory layout diagram illustrating out-of-bounds read offset calculation and adjacent static RAM exposure.
Memory layout diagram illustrating out-of-bounds read offset calculation and adjacent static RAM exposure.

← Back to IT Security