On many Linux systems, the kernel’s networking stack supports IPsec using a subsystem called XFRM. In early 2026, a vulnerability was discovered and patched—now known as CVE-2026-31664. This bug allowed attackers to leak data from the kernel’s heap memory to userspace due to uninitialized structure padding. Below, you’ll find a plain-language explanation, code samples illustrating the bug and fix, exploit details, and sources for further reading.
Impact: Attackers can read pieces of kernel memory, which may contain sensitive information.
- CVE: CVE-2026-31664
- Fixed in: Linux commit (see References)
What Happened?
A kernel *struct* (struct xfrm_user_polexpire) is used to notify userspace when a policy is about to expire by broadcasting a Netlink message. But the padding inside that struct wasn’t cleared, so leftover heap memory (which could be anything from recently-used data to actual secrets) was sent to user programs that listen for these events.
Code Before the Fix
// Vulnerable function: build_polexpire()
struct xfrm_user_polexpire {
__u8 hard; // Indicates hard expiration
// ... (other fields, with compiler-added padding after "hard")
};
int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp, int hard)
{
struct xfrm_user_polexpire *upe;
upe = nlmsg_put(skb, ...);
upe->hard = hard;
// <-- MISSING: memset_after() to clear the rest of the struct (padding)
// ...fill other fields, finalize message
}
- Problem: The compiler may add padding after the hard field. That padding contains garbage from the heap allocation, sent untouched to userspace.
The Secure Pattern
A similar struct (xfrm_user_expire) did explicitly zero padding using a helper: memset_after(). That makes sure only intentional data leaves the kernel.
// Fixed code (added line)
memset_after(upe, hard);
Why Does Padding Matter?
When you use C structs, compilers often insert extra padding to align fields for performance. If those bytes aren’t intentionally set, they’ll contain whatever random junk was last in their memory location—potentially sensitive data.
In security context: Attackers can receive these hidden bytes, analyze them repeatedly, and possibly reconstruct secrets like pointers, passwords, or keys!
Exploit Details
To pull data out, an attacker just needs to listen for XFRM “policy expire” events via Netlink. If any XFRM rules are present (and can be expired—sometimes just waiting), each event leaks small heap fragments.
> Note: An attacker needs access to netlink messages in the right group (likely CAP_NET_ADMIN or an appropriate group membership), but in some environments, this is not privileged, or could be escalated via other bugs.
You can use the pyroute2 library in Python to listen to XFRM events
from pyroute2 import NetlinkXfrm
import binascii
# Open XFRM netlink socket
nl = NetlinkXfrm()
nl.bind(groups=['expire']) # Listen for 'expire' notifications
print("Waiting for XFRM policy expiry events (CVE-2026-31664 leak demo)...")
while True:
for msg in nl.get():
print("Received message:")
print(binascii.hexlify(msg['payload']))
# The leaked kernel memory is within the message payload's padding
What Will You Find?
Each time a policy expires, you get a netlink message. The few trailing bytes after the “hard” field may show up as semi-random garbage—this is data from the kernel heap at the time.
With repeated polling and analysis, attackers may build up a picture of recent kernel activity, memory layout, or uninitialized data buffers.
Mitigation
- Upgrade your kernel! The correct fix is included in upstream Linux, see this commit.
- Admins should restrict netlink group access, monitor for suspicious listeners, and keep an eye on kernel advisories.
Details & Patch:
CVE Entry:
Netlink Sockets:
- Kernel documentation – Netlink
pyroute2 Documentation:
Conclusion
CVE-2026-31664 is a case where tiny overlooked details—like struct padding—can have a big security outcome. Always zero out memory before sending kernel data to userspace! Update your Linux systems as soon as possible to patch this heap leak. If you maintain custom kernels, review any logic that sends structs with padding out of the kernel.
Timeline
Published on: 04/24/2026 14:45:13 UTC
Last modified on: 04/27/2026 19:59:44 UTC