Skip to content
fundamentals

How should a receiver handle malformed and spam shreds?

A raw shred receiver should treat every UDP datagram as untrusted. It checks length, variant, version, slot horizon, indexes, sizes, FEC counts, proof layout, leader identity, signature, and set consistency in increasing cost order. Bounded maps, duplicate suppression, conflict isolation, rate metrics, and kernel-drop monitoring prevent malformed traffic from displacing valid current-slot work.

operations desk · updated 2026-08-31

1 hostile datagram can reach any parser

UDP has no connection handshake. Any host able to reach the listening socket can send bytes that look like shreds. Even a feed restricted by firewall rules can forward malformed network traffic or encounter local corruption and software faults.

The receiver therefore starts with zero trust. Transport source admission reduces exposure. It does not turn payload bytes into valid Solana data.

Parser safety, load control, and protocol correctness are one problem. A malformed count can cause an allocation spike. A false future slot can create permanent state. A bad proof can consume hashing. A duplicate flood can starve current data even when every individual packet is harmless.

Stage 1 checks datagram length

The service contract permits raw datagrams up to 1,228 bytes. The parser first retains actual receive length and any socket truncation indicator.

Packets shorter than the fields they claim to contain are rejected before field reads. Packets above the supported maximum are rejected or handled by an explicitly different framing path. Never read from unused buffer capacity after a short receive.

Length failures are cheap and should not allocate packet objects beyond a small bounded sample. Count too_short, too_long, and socket_truncated separately because they point to malformed senders, protocol mismatch, and local buffer errors.

Stage 2 decodes a supported variant

The one-byte variant selects data or coding, legacy or Merkle, proof size, and optional layout features. Unknown or impossible patterns stop processing.

Do not mask unfamiliar bits until the value resembles a known type. A future variant requires matching layout support. An attacker can choose high bits to steer an unsafe parser toward the wrong tail offsets.

After variant selection, verify the packet is long enough for its required header and tail. Proof-size arithmetic needs checked addition and subtraction. Underflow near the packet end is a common low-level parser defect.

Stage 3 rejects wrong lineage and horizon

The two-byte shred version must match configured cluster context. A mismatch is an inexpensive terminal decision.

Slot must fall inside a bounded window around trusted progress. Packets far behind the retained root are replay noise. Packets implausibly far ahead should not create maps or timers. The window can be asymmetric because modest reordering behind the tip is more useful than speculative distant state.

Do not move the trusted tip forward because one packet claims a huge slot. Progress comes from authenticated cluster context. Otherwise an attacker can drag the acceptance window away from real traffic.

Stage 4 bounds every integer

Common index, FEC set index, parent offset, data size, data count, coding count, coding position, and proof size all originate on the wire.

Check arithmetic for overflow. Check coding position below coding count. Check counts against supported implementation limits before allocating shard arrays. Check data index against the source range once set shape is known. Check parent subtraction for underflow.

A two-byte count is small compared with a 32-bit index but can still create thousands of buffers per fake set. Per-packet bounds and per-slot aggregate caps are both required.

Stage 5 resolves and verifies the leader

After cheap checks, obtain the expected leader identity for the claimed slot. Verify the legacy signed bytes or reconstruct and verify the Merkle root according to the variant.

Packets with unavailable schedule context can enter a small pending queue if operations expect the data soon. They should not contribute to FEC thresholds or ordered entry bytes before attribution.

Invalid signatures become known erasures, not tentative shard rows. Passing their payload into Reed-Solomon can contaminate every reconstructed source.

FEC metadata can attack memory

A spammer can vary slot, FEC anchor, data count, coding count, and root to create many apparent sets. Even one packet per key can exhaust maps if state survives long enough.

Create provisional state only after cheap filters, and prefer after authentication when latency allows. Apply caps per source, slot, active window, and total process. Evict unauthenticated and distant state before authenticated current-slot state.

Use sparse storage until dimensions are validated. A common index near the 32-bit maximum must never cause a vector resize. Presence bitmaps should be created from sanitized bounded counts, not the largest observed coordinate.

Duplicate floods attack CPU

The same valid packet can be replayed thousands of times. Full signature or proof verification on every copy wastes CPU even though no new shard rank or ledger byte is gained.

Use a fast bounded identity and content fingerprint cache after safe header parsing. A known identical authenticated packet can be dropped before repeated heavy work. Cache lifetime follows the active slot horizon.

Be cautious with unauthenticated fingerprints. An attacker can pre-seed a weak hash collision or identity to suppress the later valid packet. Strong content hashes, verification status, and replacement rules must be explicit.

Conflicts are not ordinary duplicates

Two packets claiming one slot, type, and index with different bytes need further evaluation. One may be invalid spam. Both may be authenticated leader conflicts.

Never use last-write-wins. Verify competing candidates under bounded work, partition Merkle roots or legacy set views, and keep them out of the same FEC matrix and ordered stream.

Retain a limited evidence record containing packet hashes, signatures, roots, headers, arrival times, and transport sources. Escalate authenticated conflicts. Drop unlimited unauthenticated variations after counters and small samples.

Merkle proof spam is computational

A packet can claim a Merkle variant and force hashing if proof size and layout checks are weak. Many random roots can also defeat naive positive-cache locality.

Validate proof length against packet size and set dimensions first. Compute the canonical leaf coordinate before hashing. Bound concurrent root candidates per slot and FEC anchor. Use root-signature caches only after a packet proves membership.

Negative caching can reduce repeated work for identical invalid packets, but attacker-selected random values can fill it. Use short lifetimes, size bounds, and admission sampling rather than permanent negative entries.

Entry decoding has its own bombs

Authenticated shred bytes still contain serialized length fields for vectors, entries, signatures, accounts, and instructions. A malicious or faulty leader can authenticate data that asks a generic decoder to allocate excessive memory.

Bound decoded collections using protocol and operational limits. Ensure total declared lengths fit the completed byte buffer before reserving. Reject trailing or incomplete objects. Run program-specific decoders behind further size and recursion limits.

Authentication proves who supplied bytes. It does not prove those bytes are safe input for an unconstrained serializer library.

Kernel pressure can hide valid traffic

Application validation happens after the kernel accepts datagrams. A high packet rate can overflow socket queues before user-space rejection. Valid and invalid packets then compete for the same finite buffer.

Use firewall source policy for the known relay path, adequate SO_RCVBUF settings, batch receive APIs where supported, and dedicated receive work. Monitor kernel UDP drops, interface drops, application queue depth, and per-stage rejection.

A zero application parse-error rate does not mean the feed is healthy if the kernel discarded packets first. Network and user-space counters need one dashboard.

Rate limits need protocol priorities

A flat packets-per-second limit can drop valid bursts from the current leader while allowing low-rate state exhaustion across many fake slots. Prioritization should consider trusted source, expected version, active slot window, known leader, and current assembly gaps.

Current-frontier data often has higher latency value than surplus parity for already complete sets. Coding for a blocked recoverable set can be more valuable than far-ahead data. The receiver can make these queue choices without changing protocol validity.

Rate policy should degrade explicitly. Drop unauthenticated distant traffic first, then duplicates, then unneeded completed-set parity. Record when valid candidates are shed because capacity is exhausted.

Logging can become the attack

Printing one line per malformed packet can saturate disk and CPU at a fraction of network capacity. Raw packets can also contain transaction content that should not enter general logs.

Aggregate counters by reason, variant, observed version, source, and slot bucket. Use rate-limited samples containing bounded headers and hashes. Store packet captures only under explicit short-lived diagnostic controls.

Alerts should key on rates and ratios. Ten invalid packets during a network transition mean something different from 90 percent invalid traffic. Include kernel drops so silence in parser metrics is not mistaken for recovery.

Backpressure does not exist on raw UDP

The sender does not slow because the application queue is full. The wire contract has no retransmission or backpressure. Once local capacity is exceeded, packets are dropped somewhere.

Bound every internal channel. An unbounded queue converts a transient burst into memory exhaustion and long stale latency. A bounded queue makes loss visible and allows protocol-aware drop priority.

Recovery can repair some dropped data if coding survives. It cannot repair whole FEC sets discarded by an overloaded receiver. Capacity planning should include peak traffic and attack headroom, not only the 54.3 Mbps measured mean.

Test the reject path as hard as success

Fuzz minimum lengths, every variant byte, proof-size extremes, count disagreements, position bounds, parent underflow, index overflow, wrong versions, invalid signatures, conflicting roots, and malformed serialized entry lengths.

Measure CPU and allocation per rejected packet. A correct rejection that takes 5 milliseconds is still a denial-of-service surface at thousands of packets per second.

Replay mixed captures containing valid current traffic and adversarial noise. The success criterion is not only no crash. Valid frontiers should continue advancing within the latency budget while invalid state remains bounded and observable.

Load tests should preserve realistic packet-size and burst distributions. A million tiny invalid datagrams stresses packet-rate overhead. Full-size bad Merkle packets stress memory bandwidth and hash inputs. Valid duplicate replay tests the cache. Many one-packet fake FEC anchors test state cardinality.

Set explicit invariants for the harness. Resident memory stays below a bound. Active set count stays capped. Verification queue age remains below a target for valid current-slot packets. No rejected packet reaches entry deserialization. Kernel drops are measured, not ignored. Every forced policy drop receives a bounded reason counter.

Fault injection inside the process matters too. Delay the signature pool, exhaust the packet buffer pool, stall one FEC worker, rotate the leader-schedule cache, and make the entry consumer stop reading. UDP has no backpressure, so each downstream stall should lead to a defined bounded degradation rather than hidden memory growth.

Run sanitizers and coverage-guided fuzzers against byte parsers. Property tests can assert that no accepted data size exceeds the datagram, no coding position exceeds its count, no allocation derives from an unchecked index, and no two roots contribute to one recovery matrix.

Finally, replay a clean capture after every hostile case. Recovery to normal latency is part of the requirement. A cache or slot table poisoned by invalid traffic can keep dropping good packets after the attack stops even when peak memory looked acceptable.

Record the recovery interval from the last hostile packet until valid current-slot latency returns to its normal range.

In practice

A receiver handles 5,585 legitimate packets per second from the configured relay and receives 20,000 additional datagrams per second after a firewall rule is opened too broadly.

8,000 spam packets are shorter than the 83-byte common header. 5,000 use unsupported variants. 4,000 carry the wrong shred version. 2,500 claim future slots beyond the acceptance horizon. The remaining 500 have plausible headers but invalid leader signatures.

Length, variant, version, and horizon checks reject 19,500 packets without FEC allocation or cryptographic work. A bounded verification pool handles the final 500. Duplicate caches and queue priority preserve current-slot valid traffic. Kernel drop counters remain zero. Logging emits counters and 20 sampled hashes, not 20,000 lines per second.

What this does not cover

This page provides a defensive receiver model, not a complete validator networking or denial-of-service specification. Exact protocol bounds, supported variants, leader-schedule behavior, and serialization limits must come from the Agave release and feature set the consumer supports.

Source-IP filtering reduces exposure but does not replace end-to-end validation. No admission design can guarantee lossless processing once host, kernel, or network capacity is exceeded. FEC repairs bounded erasures, not wholesale overload.

Related questions

Should a receiver trust packets from the feed source IP?
The configured source IP is appropriate for firewall admission and delivery diagnostics, but payloads still require Solana protocol validation. The relay address is not the slot leader identity. Length, variant, version, header bounds, leader signature or Merkle proof, and FEC consistency remain end-to-end receiver responsibilities.
Which checks should run before signature verification?
Check actual datagram length, supported variant, required layout size, expected shred version, slot horizon, index bounds, data size, FEC counts, coding position, and proof-size arithmetic first. These inexpensive gates prevent unsafe reads, large allocations, and avoidable cryptographic work on traffic that cannot be admissible.
How should duplicate shred floods be handled?
Use a bounded cache keyed by shred identity and a strong content fingerprint tied to verification status. Repeated identical authenticated packets add no FEC rank or ledger bytes and can be dropped early. Different content under one identity requires conflict handling rather than duplicate suppression or last-write-wins replacement.
Why are untrusted FEC counts dangerous?
Data and coding counts determine matrix dimensions, buffers, and presence maps. Allocating directly from unchecked packet values allows small datagrams to create large memory commitments across many fake sets. Receivers must enforce implementation-aware per-field bounds, cross-member agreement, per-slot caps, and a global active-state budget.
Can FEC recover packets dropped during receiver overload?
FEC can recover missing data only when enough distinct valid members of each affected set survive. Selective loss of a few data packets may be repaired by coding shreds. Broad queue overflow can discard data and parity together, leaving fewer members than the source threshold and making local reconstruction impossible.

Read next

Ready to build against this? The documentation covers the implementation.