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.
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.
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.