About LucidBit Labs
LucidBit Labs is a security research firm specializing in security audits for high-risk, complex systems. Our team is comprised of top tier researchers with an offensive mindset, using internal tools and methodologies, a combination that leads to an extremely effective process.
Firedancer is a high-performance Solana validator client designed for extreme throughput and low-latency packet processing. Validators are the backbone of the blockchain. They are critical for the correct operation of the blockchain, and as such, they are highly sensitive to security issues.
Firedancer's developers placed a strong emphasis on security, and the result is high quality code. While most validator software undergo security audits, Firedancer was designed with robust security in mind. It is comprised of sandboxed components (tiles), inspired by methods used in the browser world which is under perpetual attack.
In Short
The core bug: the XDP logic used the IPv4 header-length field (IHL) to derive the next-header offset before confirming that the value was valid. The result was parser disagreement 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. Issues with limited impact are often quickly scratched off as low severity, but a motivated attacker can sometimes find a way to exploit them.
Our team leveraged GRE to do just 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.
Cases like this are a useful reminder that, in packet-facing native systems, exploitability often depends less on the initial bug pattern than on whether the real delivery path can be recovered and validated against the implementation.
From narrow parser bug to remotely deliverable issue
Packet-facing native infrastructure fails differently from conventional application software. A single unchecked structural assumption can become a crash primitive before any application-layer logic is reached. In validator infrastructure, that is not just a reliability problem. Availability is part of the security model.
The key lesson is how exploitability was established. The team started from exposed attack surfaces, identified which packet invariants the fast path assumes have already been checked, verified that each parsing stage still agrees on structure after decapsulation, and kept looking at delivery assumptions when the initial trigger looks operationally narrow. That process 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.
That distinction matters even more here because Firedancer's packet filtering logic is generated as an XDP/eBPF program. XDP gives very fast packet processing in the kernel fast path, and the eBPF verifier checks that the program is memory-safe at the bytecode level before it can run.
The verifier, however, does not prove that protocol-derived offsets are semantically correct. It can approve packet pointer arithmetic that remains technically in bounds even when the protocol field used to derive the pointer was structurally invalid. In other words, an invalid IHL can still yield a logically wrong next-header pointer that the verifier will not reject.
Exact vulnerable path in the affected 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.
The fix
The upstream patch that fixed the issue (commit 933d900) 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 affected code, the downstream crash is consistent with assumptions in Firedancer's later packet-processing path that the net/XDP layer had 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 */
The comment implies the trust relationship: 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 a crucial part here. Initially, the malformed packet shape did not look cleanly remote, because the malformed packet would not 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.
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
Team response: the Firedancer team handled the issue extraordinarily quickly and professionally.
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 933d900 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.
How LucidBit Labs can help
LucidBit Labs helps teams that develop sensitive systems by identifying critical security issues through exploitability-driven security research grounded in real code paths and realistic attacker delivery models. Get in touch if that is relevant to your system.