Case Study · Exploitability-Driven Security Research

Remote Unauthenticated Memory Corruption in Firedancer's Packet Path

A malformed IPv4 header-length field looked like a narrow parser bug at first. By recovering a realistic GRE delivery path and tying the trigger to the concrete XDP code path, we showed it was a remotely deliverable, unauthenticated crash against packet-facing validator infrastructure.

By Almog, Julia, Lior · 2026-03-15

Remote Unauthenticated Memory Corruption in Firedancer's Packet Path

At a glance

Target: Firedancer XDP packet-handling path

Bug class: Remote unauthenticated memory corruption

Root cause: IPv4 <code>IHL</code> trusted before minimum-size validation

Exploitability pivot: GRE preserved the malformed inner packet

Demonstrated impact: Reliable validator crash

Outcome: Fixed upstream · $100,000 bounty awarded via Immunefi

LucidBit Labs is a security research firm specializing in security audits for high-risk, complex systems, leveraging top-tier researchers with an offensive mindset.

Why this post matters

During research on Firedancer, Solana's high-performance validator client, we found a remote unauthenticated memory-corruption issue in the packet path. The core bug was small: the XDP logic used the IPv4 header-length field (IHL) to derive the next-header offset before confirming that the value was structurally legal. The result was parser disagreement, memory corruption, and a reliable crash.

What made the finding important was not just the bug class. It was the exploitability work. The original malformed trigger looked operationally constrained, because the packet shape would not normally survive routing unchanged. GRE changed that. By embedding the malformed inner IPv4 packet inside a routable outer IPv4 packet, we preserved the dangerous condition long enough to reach Firedancer's packet path remotely and without authentication.

This is exactly the kind of case that matters to teams buying serious software security audits: the vulnerability was subtle, packet-facing, native-code-specific, and only fully meaningful once the delivery path was recovered and tied to the real implementation.

Why the methodology matters

Packet-facing native infrastructure fails in ways that are different from conventional application software. A single unchecked structural assumption can become a crash primitive long before any application-layer logic is reached. In validator infrastructure, that is not a mere reliability issue. Availability is part of the security model.

That is why the important signal here is methodological rather than promotional: start at an attacker-controlled boundary, identify what fast-path code assumes has already been validated, trace whether every stage agrees on packet structure, and keep pushing when the first delivery path appears constrained. That combination is what turned a malformed-header condition into a remotely deliverable denial-of-service.

Technical overview

The vulnerable behavior centered on the IPv4 IHL field. In IPv4, the minimum legal header length is 20 bytes, represented by IHL >= 5. In the vulnerable path, Firedancer used an IHL-derived offset before enforcing that minimum. That let attacker-controlled data influence where the parser believed the next protocol header began.

Once that happens, adjacent stages can stop agreeing on structure. One stage interprets bytes according to a malformed layout, while downstream logic continues under assumptions that only hold for a valid IPv4 header. In packet-facing native systems, that kind of disagreement is often enough to turn malformed input into memory-unsafe behavior.

It is worth noting that the eBPF verifier enforces memory-safety at the bytecode level — bounds checks on map access, stack access, and packet pointer arithmetic — but it does not enforce semantic correctness of protocol-level offset derivations. A structurally invalid IHL value can produce a technically in-bounds but logically wrong pointer that the verifier will not reject.

Exploit flow diagram showing the attack chain from attacker through outer IPv4, GRE encapsulation, malformed inner IPv4 packet, Firedancer packet parsing, to node crash.
Exploit flow: a routable outer IPv4 packet carries a GRE-encapsulated malformed inner IPv4 packet, preserving the trigger condition long enough to reach Firedancer's packet path and crash the node.

Exact vulnerable path in the uploaded code

The relevant code lives in src/waltz/xdp/fd_xdp1.c, inside fd_xdp_gen_program. The generated eBPF program advances from the Ethernet header to IPv4, extracts IHL, shifts it left by two to obtain a byte count, and immediately uses that value to derive the next-header pointer.

/* src/waltz/xdp/fd_xdp1.c — outer IPv4 path */
*(code++) = FD_EBPF( ldxb, r4, r2, 0 );      // r4 = ip4_hdr->verihl
*(code++) = FD_EBPF( and64_imm, r4, 0x0f );  // r4 = ip4_hdr->ihl
*(code++) = FD_EBPF( lsh64_imm, r4, 2 );     // r4 = ip4_hdr->ihl * 4
*(code++) = FD_EBPF( add64_reg, r4, r2 );    // r4 = start of next hdr

The same pattern appears again after GRE decapsulation for the inner IPv4 header:

/* src/waltz/xdp/fd_xdp1.c — GRE inner IPv4 path */
*(code++) = FD_EBPF( ldxb, r4, r2, 0 );      // r4 = inner ip4_hdr->verihl
*(code++) = FD_EBPF( and64_imm, r4, 0x0f );  // r4 = inner ip4_hdr->ihl
*(code++) = FD_EBPF( lsh64_imm, r4, 2 );     // r4 = inner ip4_hdr->ihl * 4
*(code++) = FD_EBPF( add64_reg, r4, r2 );    // r4 = start of udp_hdr

That is the broken invariant in one place: derive second, validate first was reversed. If IHL is smaller than the legal minimum, the derived pointer no longer references a valid post-IPv4 boundary.

What the upstream fix changed

The upstream patch that fixed the issue (commit 933d90080c879f281a7b85c12bfa26dba08ab2ca) added an explicit minimum-header-length guard before the pointer derivation on both the outer and inner IPv4 paths:

/* fix in src/waltz/xdp/fd_xdp1.c */
*(code++) = FD_EBPF( ldxb, r4, r2, 0 );
*(code++) = FD_EBPF( and64_imm, r4, 0x0f );
*(code++) = FD_EBPF( lsh64_imm, r4, 2 );
*(code++) = FD_EBPF( jlt_imm, r4, 20, LBL_PASS );  // reject IHL < 20 bytes
*(code++) = FD_EBPF( add64_reg, r4, r2 );

The same guard was added to the GRE inner-IPv4 path as well. That is the right fix pattern for this class of bug: establish the structural invariant before attacker-controlled fields influence offsets, pointer movement, or next-protocol parsing.

How the crash surfaced downstream

The practical impact was not just parser confusion. In the uploaded code, the downstream crash is consistent with assumptions in the shred path that the net/XDP layer already enforced safe structure. The relevant assertion is in src/disco/shred/fd_shred_tile.c:

ulong hdr_sz = fd_disco_netmux_sig_hdr_sz( sig );
FD_TEST( hdr_sz <= sz ); /* Should be ensured by the net tile */

That comment matters. It shows the trust relationship clearly: later code assumes earlier packet handling has already guaranteed a safe header size. Once the malformed condition survives long enough to violate that assumption, the result is operationally meaningful failure rather than a harmless malformed-packet rejection.

ERR 11-22 16:35:58.117796 shred:0 src/disco/shred/fd_shred_tile.c(671): FAIL: hdr_sz <= sz
ERR 11-22 16:35:58.122781 pidns src/app/shared/commands/run/run.c(454): tile shred:0 exited with code 1
ERR 11-22 16:35:58.124000 main src/app/shared_dev/commands/dev.c(234): firedancer exited unexpectedly with code 1

Exploitability pivot: GRE made the trigger remotely deliverable

The exploitability pivot is the part of this case that matters most to experienced buyers and researchers. Initially, the malformed packet shape did not look cleanly remote, because the trigger would not ordinarily survive routing in its original form. That could have been the end of the story in a shallow review.

Instead, the right question was whether the malformed inner packet could be preserved inside a routable outer packet without losing the dangerous property. GRE provided that path. The outer IPv4 packet satisfied delivery requirements, while the inner IPv4 packet preserved the invalid IHL that later drove parser disagreement.

Annotated packet layout showing outer IPv4 and GRE layers preserving delivery while the malformed inner IPv4 header carries the invalid IHL.
Annotated packet layout: the outer IPv4 and GRE layers provide delivery, while the malformed inner IPv4 header preserves the trigger condition that reaches Firedancer's parser.

Attack conditions and scope

The demonstrated impact is a remote unauthenticated crash for deployments where hostile GRE-encapsulated IPv4 traffic can reach the relevant Firedancer packet path. That is an exposure question, not an authentication question. No application-layer session, prior compromise, or privileged position was required once the malicious traffic reached the parser.

Being precise here matters. The core security property is not that every deployment is exposed in exactly the same way; it is that the bug sits directly on an attacker-controlled network boundary, and a realistic tunnel/encapsulation path can preserve the malformed condition long enough to make the failure remotely triggerable.

Evidence and regression coverage

The upstream changes did the right thing in two ways: they fixed the unsafe derivation pattern in fd_xdp1.c, and they strengthened regression coverage in src/waltz/xdp/test_xdp_ebpf.c around malformed IPv4 header lengths and GRE-encapsulated cases. That combination is important. Parser bugs are easy to patch narrowly and easy to reintroduce unless the tests explicitly cover the structural edge cases that made the bug exploitable.

Remediation status

Discovery context: identified during offensive research on Firedancer's packet ingress path.

Proof of concept: a working POC was developed demonstrating remote, unauthenticated crash via GRE-encapsulated malformed IPv4 traffic.

Upstream fix: commit 933d90080c879f281a7b85c12bfa26dba08ab2ca updated the XDP generator to reject undersized IPv4 headers before deriving next-header pointers, including the GRE inner-IPv4 path.

Fix verification: the upstream patch was independently verified by our team to confirm the vulnerability was fully resolved.

Publication: this write-up is being published after remediation, with unnecessary operational detail omitted.

Lessons for teams building packet-facing native systems

Validate structural invariants before deriving offsets. If a field controls pointer movement or header layout, validate its legal range first.

Keep parser stages aligned. Filters, decapsulation logic, transport dispatch, and downstream consumers need a shared view of what constitutes a valid packet shape.

Model tunnels and encapsulation paths. A routing constraint is not the same thing as an exploitability barrier. Outer protocols often preserve malformed inner state.

Treat crash-only outcomes seriously in distributed infrastructure. In validators and other consensus-adjacent systems, reliable unauthenticated crashes can be security-significant even without code execution.

Closing note

The Firedancer team handled the report professionally and fixed the issue. For us, the more durable takeaway is that serious bugs in performance-critical systems often hide in the boundaries between parser stages, not in obviously dramatic code.

If you maintain packet-facing native infrastructure — validators, custom transport layers, runtimes, parsers, or other performance-critical network services — and want this level of exploitability-driven review applied to your system, request a security assessment.