Table of contents
Overview
The Orca Security Research Pod discovered a use-after-free race condition in the Linux kernel’s ksmbd SMB3 server. When two connections share a session over SMB3 multichannel, the kernel can read a freed channel struct – exposing the per-channel AES-128-CMAC signing key and causing a kernel panic. An attacker needs valid SMB credentials and network access to port 445. No exotic prerequisites. The fix is merged (commit e4a8a96a93d) – update your kernel.
| Attribute | Details |
|---|---|
| CVE | CVE-2026-23226 |
| Researcher CVSS | 7.5 High – AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H |
| NVD CVSS | 7.8 High – AV:L/AC:H (under dispute – see scoring note) |
| CWE | CWE-416 (Use After Free), CWE-362 (Race Condition) |
| Affected Component | Linux kernel ksmbd SMB3 server – ksmbd_chann_list XArray |
| Bug Introduced | commit 1d9c4172110e (Dec 2023) – channel list converted to XArray without synchronization |
| Confirmed Affected | Linux kernels containing commit `1d9c4172110e` without `e4a8a96a93d` (approx. 5.15.145+, 6.1.x select builds, 6.7 through 6.19.0) |
| Attack Vector | Network – SMB3 port 445 |
| Authentication | Low – valid SMB user credentials required |
| Exploit Complexity | High – race condition, ~1 hit per 750 attempts |
| Active Exploitation | None confirmed |
| PoC Available | Yes – developed and confirmed by Orca Security Research Pod |
| Fix | Merged – commit e4a8a96a93d (stable), upstream 4f3a06cc579 |
| Discovered By | Orca Security Research Pod |
| Patch Author | Namjae Jeon, ksmbd maintainer |
| Coordination | Greg KH, Steve French, kernel security team |
What Is ksmbd – and Why Does It Matter?
Most Linux administrators know Samba – the long-standing userspace daemon that lets Linux servers share files with Windows clients over SMB. ksmbd is its younger, kernel-native counterpart. Merged into mainline Linux in kernel 5.15 (November 2021), it implements the SMB2/3 protocol entirely inside the kernel for better performance – no context switches to userspace for every request.
That architectural choice has a direct security consequence: a vulnerability in ksmbd is a kernel vulnerability. It doesn’t compromise a process running as root. It compromises the kernel itself – full machine takeover territory.
ksmbd has accumulated a notable list of serious bugs since its merge. The pattern is consistent: complex concurrent state management introduced without adequate locking. Before CVE-2026-23226, notable examples include CVE-2022-47939 (unauthenticated out-of-bounds write leading to RCE), CVE-2023-32254 (TOCTOU race in session setup), CVE-2023-32257 (use-after-free), and, directly related to this finding, CVE-2025-40039. That last one is worth understanding, because CVE-2026-23226 is essentially the same mistake made twice.
CVE-2025-40039 involved the rpc_handle_list XArray inside struct ksmbd_session – another sparse array used to track shared mutable state across threads. It had no lock. The fix added rpc_lock (a read-write semaphore). That fix was applied in 2025. But ksmbd_session has three XArrays. Only one was fixed. The ksmbd_chann_list XArray – used to track multichannel connections – was left unprotected. CVE-2026-23226 is that oversight.
Understanding SMB3 Multichannel
To understand the vulnerability, you need to understand what multichannel is and why it creates concurrent access to the channel list.
- SMB3 Multichannel – introduced in Windows Server 2012 / SMB dialect 3.0. Allows a single authenticated SMB session to use multiple TCP connections simultaneously, spreading I/O across multiple network interfaces for throughput. From the server’s perspective, a single
ksmbd_sessionobject must track all active TCP connections as “channels,” stored in theksmbd_chann_list XArray.
The setup requires two distinct phases. First, the client authenticates over a primary TCP connection using full NTLM authentication – this is standard SMB3. Then, for each additional connection (channel), the client sends a special SESSION_SETUP request with a flag set: SESSION_FLAG_BINDING = 0x01. This binding request references the already-authenticated session ID and must be signed with the session’s AES-128-CMAC key.
When ksmbd sees that binding flag, it takes a completely different code path – the binding_session label in smb2_sess_setup(). This is the path where the race lives.

The binding path has a strict set of requirements ksmbd validates before proceeding:
- Dialect must match the primary connection
- Request must be signed (
SMB2_FLAGS_SIGNED) ClientGUIDmust match the primary session- Session must be in
SMB2_SESSION_VALIDstate
All of these are checked correctly. The bug isn’t in the validation. It’s in what happens after, when ksmbd looks up the channel list to register the new connection.
The Vulnerability – A Missing Lock
The Broken Data Structure
struct ksmbd_session tracks three types of shared mutable state, each in its own XArray. Here’s the problem in plain sight:

Two out of three XArrays got locks. The channel list was left bare.
- XArray – a kernel sparse array structure (Linux 4.20+) that maps integer keys to pointers. ksmbd uses
ksmbd_chann_listto map TCP connection pointers tostruct channelobjects. The key operations arexa_load()(read an entry) andxa_erase()(atomically remove and return an entry). These two operations are not safe to call simultaneously from different threads without external locking, the XArray’s internal lock only protects modifications against other modifications, not a reader against a concurrent erase.
The Vulnerable Code
The read path – called from the channel binding handler, performs a bare xa_load() with no lock held:

The delete path – triggered during session logoff, calls xa_erase() then immediately kfree(), also with no lock:

Note the use of kfree() rather than kfree_rcu(). RCU (Read-Copy-Update) is the standard kernel mechanism for safely freeing objects that concurrent readers might still hold. Not using it means the memory is freed immediately, with no grace period for in-flight readers to finish. Combined with no lock on the read side, this is a textbook use-after-free setup.
What Gets Freed and Read
struct channel is a 24-byte object (kmalloc-32 slab):

Three call sites in smb2pdu.c dereference the returned channel pointer to read the signing key, without any synchronization:

The signing key is the AES-128-CMAC key used to verify every SMB3 packet on this channel. Reading it from freed memory means either reading garbage (signature verification will fail with corrupted data) or reading the original key if the allocator hasn’t reused the slot yet (signing key exposure).
Why the race window is wide
The critical enabling factor is ksmbd_conn_wait_idle(). During connection teardown, ksmbd calls this function to drain in-flight work before freeing the connection’s resources. But it only drains the work queue of the specific connection being torn down – not all connections that share the same session.
This means: when conn2 tears down and calls ksmbd_chann_del() to free conn1’s channel struct, conn1’s worker threads may still be processing signed requests that call lookup_chann_list(). There is no session-level barrier. The teardown of one connection races freely against the ongoing work of another connection in the same session.

On a 4-core machine with ksmbd’s concurrent ksmbd-io worker thread pool, this window is wide enough to hit reliably – our PoC fires 8–11 times per 500-iteration run with the first hit typically within 60–120 seconds.
Impact
What an attacker achieves
The race produces three possible outcomes, depending on timing and allocator state:
Signing key leak. If the kmalloc-32 slab slot hasn’t been overwritten by the time lookup_chann_list() reads it, the UAF returns the original 16-byte smb3signingkey. This is the per-channel AES-128-CMAC key used to sign all SMB3 traffic on that channel. An attacker who recovers this key can forge signatures, impersonate the server, or bypass signature verification entirely for the duration of the session.
Signature bypass via garbage key. Even if the slot has been partially overwritten, ksmbd will use whatever garbage bytes it reads as the signing key. Server-side signature verification will silently accept or reject packets based on corrupted state – undermining the integrity guarantees that SMB3 signing is supposed to provide.
Kernel panic (DoS). The struct channel contains chann->conn at offset 16 – a pointer to the connection object. If the freed slot gets reallocated and partially overwritten, dereferencing this pointer causes a kernel panic. This is the most reliably observable outcome and what our PoC consistently triggers on KASAN builds.
What this is not
The current PoC does not achieve kernel code execution. It proves the UAF reliably and triggers a kernel crash. Converting a race-based UAF to full RCE requires additional work: confirming a write UAF path, heap grooming in kmalloc-32, building a KASLR bypass from the information leak, and constructing a full exploit chain. That is a realistic multi-month research effort – and a separate project. We’re disclosing at UAF confirmation because that’s the honest and correct point to disclose. The vulnerability is real, the impact is significant, and the fix is available.
Who is Affected
| Environment | Risk |
|---|---|
| Linux kernel since Dec 2023 + ksmbd + multichannel enabled | Affected |
| Linux kernel before commit 1d9c4172110e (Dec 2023) | Not affected – bug not yet introduced |
| ksmbd running but multichannel not configured | Significantly reduced – binding code path unreachable |
| Samba (smbd, not ksmbd) | Not affected – separate implementation |
| No SMB server running | Not affected |
CVSS scoring note
Our researcher assessed score is 7.5 High with Attack Vector: Network (AV:N). The attack requires sending SMB3 packets to port 445 from a remote machine – no local access. NVD currently scores it 7.8 High with AV:L (Local), which we believe is incorrect. Notably, correcting the vector to AV:N actually lowers the score from 7.8 to 7.5 – this is a technical accuracy dispute, not an attempt to inflate severity. A formal CVSS dispute has been filed referencing this post.
The Fix
Namjae Jeon (ksmbd maintainer) sent the patch the morning after our disclosure. We reviewed it, confirmed it covered all five access points, and it was committed by Greg KH on February 16, 2026.
- Stable tree commit:
e4a8a96a93d08570e0405cfd989a8a07e5b6ff33 - Upstream commit:
4f3a06cc57976cafa8c6f716646be6c79a99e485 - Reported-by: Igor Stepansky, Orca Security (credited in kernel git)
- Submitted for stable backport (
Cc: stable@vger.kernel.org)
The fix adds one field to struct ksmbd_session:

And protects all five access points. The key subtlety in ksmbd_chann_del() – the write lock wraps only the xa_erase(), then releases before kfree(). This is intentional: the lock guards the XArray from concurrent access. Once the pointer is removed from the array and no other holder exists, the free needs no lock.

free_channel_list() and both xa_store() call sites in the session binding path are also wrapped with down_write/up_write in the patch.

Proof of Concept
Background: why this PoC was hard to build
When we initially disclosed to the kernel security team, we noted that no KASAN-triggering PoC existed. The problem: triggering the race requires a custom SMB3 client that implements channel binding with SESSION_FLAG_BINDING = 0x01, correct AES-128-CMAC signing, and matching dialect negotiation. No existing tool – smbclient, Impacket, or otherwise – does this out of the box.
Building the PoC took five iterations:
- v1 – Used Impacket’s high-level
login()twice. Never reached the binding path because Impacket always sendsFlags = 0. No UAF. - v2 – Sent raw SMB2 packets with
SESSION_FLAG_BINDING = 0x01. GotSTATUS_INVALID_PARAMETER. Root cause: secondary connection negotiated SMB 3.0 while primary used SMB 3.1.1 – ksmbd checks dialect match and rejects. - v3 – Matched the dialect. Still
STATUS_INVALID_PARAMETER. Root cause:Capabilitiesfield packed as 2 bytes (<H) instead of 4 (<I), corrupting the entire packet body. - v4 – Fixed packet structure. Now getting
STATUS_USER_SESSION_DELETED. Root cause: signed with HMAC-SHA256 instead of AES-128-CMAC. SMB 3.0 uses AES-128-CMAC for signing – wrong algorithm means signature verification fails. - v5 – Instead of reimplementing SMB3 signing from scratch, patched Impacket directly. One line change. Impacket handles everything – NTLM auth, correct dialect, correct signing – we just set the right flag.
The final insight: don’t fight the protocol stack, patch the one missing feature.
Required: Impacket Patch

Setting smb3._binding = True on a connection object causes its next SESSION_SETUP to send SESSION_FLAG_BINDING = 0x01. All signing, NTLM, and dialect handling stay in Impacket’s existing implementation – unchanged.
PoC Code



Lab environment
The PoC was confirmed on Linux 6.12.0 in a KASAN-enabled QEMU/KVM VM on bare metal Ubuntu 24.04:
CONFIG_KASAN_GENERIC=y– makes the UAF visible as a clean crash reportCONFIG_RANDOMIZE_BASE=n– KASLR disabled for lab convenience only, doesn’t affect UAF triggeringkasan_multi_shot=1boot parameter – KASAN keeps reporting after the first hit rather than going silent, essential for measuring hit rate- 4 vCPUs – genuine SMP parallelism, the race requires concurrent kernel threads on separate cores
- KASAN (Kernel Address Sanitizer) – a kernel debug tool that tracks memory validity using shadow memory. For every 8 bytes of real kernel memory, 1 byte of shadow memory records whether those bytes are safe to access. When freed memory is touched, KASAN catches it immediately and prints full allocation and free stack traces. KASAN is only used in debug kernels – production kernels don’t have it, which means the same race causes a silent crash or kernel panic instead of a clean report.
KASAN output – confirmed

The PoC runs on the attacker machine (right) and sends SMB3 packets over the network to the VM running ksmbd (left). Within ~2 minutes, the race fires and KASAN reports the UAF in real time
Split-screen: VM terminal (left) showing BUG: KASAN: slab-use-after-free in smb2_sess_setup+0x4300/0x5f80 appearing. Host terminal (right) showing [*] Round 100/500. Both visible simultaneously – network attack on the right, kernel crash on the left.
The KASAN splat from our run:

Reading the splat: Thread 38687 allocated the object during session login. Thread 28565 freed it during logoff. The same thread 28565 then attempts to read it in the binding path – KASAN catches the access to the freed kmalloc slab.
The race fires across all four CPUs in our VM:

Hits on CPUs 1, 2, and 3 independently – this is a genuine SMP race across ksmbd’s worker thread pool, not a single-threaded timing artifact.

A note on the KASAN object size: Our KASAN output shows a kmalloc-64 object allocated by ksmbd_alloc_user. The original vulnerability report describes the UAF on the 24-byte struct channel (kmalloc-32) via smb3_check_sign_req(). Both paths involve the same missing lock on ksmbd_chann_list – our PoC happened to trigger a related object free in the same logoff path. The struct channel / smb3signingkey path described in the original report is the most security-sensitive impact (signing key exposure), the kmalloc-64 hit confirms the broader locking gap.
Remediation
The fix is available now.
Update to a kernel containing commit e4a8a96a93d08570e0405cfd989a8a07e5b6ff33. The patch has been officially released – check your distribution’s kernel security advisories for when it lands in your specific branch.
| Deployment | Action |
|---|---|
| ksmbd + multichannel enabled | Disable multichannel if not required: remove ksmbd: smb3 multichannel = yes from smb.conf, restart ksmbd |
| ksmbd + multichannel not configured | Lower risk – the binding code path is unreachable. Verify with grep -r multichannel /etc/ksmbd/ |
| Samba (smbd, not ksmbd) | Not affected |
| No SMB server running | Not affected |
Check if you’re running ksmbd:

Interim mitigations if multichannel cannot be disabled:
- Firewall port 445 to known trusted client IP ranges – reduces the attacker pool to your internal network
- Minimize valid SMB accounts – every valid credential is a potential attacker credential for this vulnerability
- Monitor for abnormal SESSION_SETUP request volume (see Detection)
Detection
On a production kernel (no KASAN), the UAF doesn’t produce clean output. Production kernels will show a generic kernel oops rather than a UAF report. Watch dmesg and journalctl -k for:

These are suspicious when appearing in the context of kworker threads and ksmbd stack frames.
Network-level: The PoC sends dozens of SESSION_FLAG_BINDING requests per minute against the same session ID. Legitimate multichannel usage binds a handful of channels per session and holds them – it does not rapidly cycle bind/logoff. Detect with:


The entire vulnerability in two functions. lookup_chann_list() is two lines with no lock. ksmbd_chann_del() frees the same pointer concurrently. Nothing coordinates them.
Frequently Asked Questions
No. Samba (smbd) is a completely separate userspace SMB implementation and is not affected. This vulnerability is specific to ksmbd – the kernel-native server. You can tell which you’re running with ps aux | grep ksmbd.mountd (ksmbd) vs ps aux | grep smbd (Samba).
No. It requires explicitly adding ksmbd: smb3 multichannel = yes to /etc/ksmbd/smb.conf. Most ksmbd deployments don’t have this configured, which means the binding code path – and therefore this vulnerability – is unreachable for them.
Once your kernel includes commit e4a8a96a93d, yes. The patch is in mainline and submitted for stable backport. Check your distribution’s kernel changelog. If you can’t update yet, disabling multichannel in smb.conf removes the attack vector entirely.
No. Valid SMB credentials are required. SESSION_FLAG_BINDING is only accepted after a primary session has been fully authenticated – the kernel checks sess->state == SMB2_SESSION_VALID before entering the binding path. This limits the attacker pool to users who already have legitimate SMB access.
NVD scores this with AV:L (Local attack vector). We assess AV:N (Network) – the attack is triggered entirely by sending SMB3 packets to port 445. No local access is required. With AV:N, the correct score is 7.5. Notably, correcting NVD’s vector lowers the score rather than raising it – this is a technical accuracy dispute. A formal dispute has been filed.
Timeline
| Date | Event |
|---|---|
| February 8, 2026 | Disclosed to kernel security team by Orca Security Research Pod |
| February 9, 2026 | Patch authored by Namjae Jeon, reviewed and confirmed by Orca Security |
| February 9, 2026 | Greg KH waived embargo – no working PoC at time of disclosure, fix pushed immediately |
| February 16, 2026 | Patch committed to mainline Linux by Greg KH – commit e4a8a96a93d |
| February 18, 2026 | CVE-2026-23226 published |
| March 2026 | PoC developed – required custom multichannel binding client; 5 iterations |
| March 16, 2026 | KASAN confirmation – 8 reliable hits in single run |
| March 17, 2026 | 11 additional hits confirmed, demo video recorded |
| March 2026 | This blog post and PoC published |
Credits
- Discovered and reported by: Orca Security Research Pod (Reported-by in kernel commit
e4a8a96a93d) - Patch authored by: Namjae Jeon (linkinjeon@kernel.org), ksmbd maintainer
- Signed off by: Steve French (stfrench@microsoft.com), ksmbd co-maintainer
- Committed by: Greg Kroah-Hartman (gregkh@linuxfoundation.org), February 16, 2026
- Prior related fix: CVE-2025-40039 (same bug class,
rpc_handle_listXArray) – thechann_lockpattern in this fix mirrors that one directly
How Can Orca Help?
CVE-2026-23226 presents a triage challenge that traditional security tools struggle with: exploitability depends on three conditions aligning simultaneously, and verifying them across a large cloud environment without logging into every asset is not feasible. Orca’s agentless SideScanning architecture was built exactly for this scenario.
In a single query, Orca scans your entire cloud environment and surfaces every Linux asset where ksmbd is present and port 445 is internet-exposed – no agents, no credentials, no access to the machines themselves. What would take a security team days of manual work across hundreds of assets takes Orca seconds:

The output is a precise, prioritized list of assets that combine internet exposure on port 445 with ksmbd presence – the two strongest remote indicators that all three exploitability conditions could be met.
The only step that goes beyond what Orca can express in a single query is the exact kernel version range (5.15.145 – 6.19.0), since kernel versions are stored as free-form strings with distro-specific suffixes. A simple post-filter script on the exported results closes that gap in minutes.
From there, Orca’s internet accessibility scoring and lateral movement graph tell you exactly how much each flagged asset matters – which ones are directly reachable from the internet, what sensitive data or downstream systems they connect to, and where to focus remediation effort first. That combination of agentless discovery, precise signal, and business context is what separates a list of potentially vulnerable machines from an actionable remediation plan.
