Neither TCP nor UDP has any encryption or authentication of its own, so anyone on the network path can read every header field and every byte of payload, and can change, drop or inject packets. TLS 1.3 over TCP protects the payload but leaves the whole TCP header exposed and forgeable, while QUIC over UDP encrypts the payload and most of its own transport header, yet both still reveal IP addresses, ports, packet sizes and timing.
That is the short answer. The useful answer is more specific, because "visible" and "changeable" mean different things depending on where the attacker sits. Someone on the path, such as a compromised router, a rogue Wi-Fi access point or a tapped link, sees everything and can rewrite packets. Someone off the path cannot see your packets at all and has to guess the numbers that make a forged packet acceptable. Most TCP and UDP attack history, from sequence number prediction in 1985 to DNS cache poisoning in 2008, is about how hard that guessing is. This post covers both headers field by field, what TLS and QUIC hide, the classic attacks as concepts and the defences that work, checked against the RFCs.
Key takeaways
- TCP (RFC 9293, August 2022, which replaced RFC 793) and UDP (RFC 768, 28 August 1980) were designed with no cryptographic protection. RFC 9293 says plainly that TCP has "no built-in cryptographic capabilities" for confidentiality or authentication.
- The TCP header carries ports, sequence and acknowledgment numbers, flags, window size and options in the clear. The UDP header is only 8 bytes: two ports, a length and a checksum. Checksums detect accidental corruption, not tampering, because anyone who changes a packet can recompute them.
- TLS 1.3 (RFC 8446) encrypts application data and every handshake message after the ServerHello, but it does not protect any TCP header field, so a forged reset can still tear down a TLS connection.
- QUIC (RFC 9000 and RFC 9001, May 2021) runs over UDP, encrypts its payload including acknowledgments and masks the packet number. It still exposes connection IDs, and the server name unless Encrypted Client Hello (RFC 9849, March 2026) is used.
- Off-path attacks depend on guessing. Keyed initial sequence numbers (RFC 6528, now in RFC 9293), stricter reset handling (RFC 5961) and DNS source port randomisation (RFC 5452) make guessing impractical.
- UDP has no handshake, so spoofing is cheap and powers reflection attacks with amplification factors CISA puts between about 2 and 51,000. Ingress filtering (BCP 38, RFC 2827) is the network level fix.
A short dated timeline
| Date | Event | Source |
|---|---|---|
| 28 Aug 1980 | UDP specified in RFC 768 | RFC 768 |
| Sep 1981 | TCP specified in RFC 793 | RFC 9293, section 1 |
| 1985 | Morris describes guessing TCP initial sequence numbers to impersonate a trusted host | RFC 6528, section 1 |
| May 1996 | RFC 1948 proposes keyed, per connection initial sequence numbers | RFC 1948 |
| May 2000 | RFC 2827 (BCP 38) recommends ingress filtering of spoofed source addresses | RFC 2827 |
| Aug 2007 | RFC 4987 documents SYN flooding and defences including SYN cookies | RFC 4987 |
| 8 Jul 2008 | CERT/CC publishes VU#800113 on practical DNS cache poisoning | CERT/CC |
| Jan 2009 | RFC 5452 sets out resolver defences against forged DNS answers | RFC 5452 |
| Aug 2010 | RFC 5961 hardens TCP against blind in-window reset and injection | RFC 5961 |
| Feb 2012 | RFC 6528 puts the keyed ISN algorithm on the Standards Track | RFC 6528 |
| 2014 | CISA alert TA14-017A on UDP based amplification attacks; last revised 18 Dec 2019 | CISA |
| Aug 2018 | TLS 1.3 (RFC 8446) | RFC 8446 |
| May 2021 | QUIC version 1 (RFC 9000) and QUIC TLS (RFC 9001) | RFC 9000, RFC 9001 |
| Aug 2022 | RFC 9293 consolidates TCP and obsoletes RFC 793 and RFC 6528 | RFC 9293 |
| Mar 2026 | TLS Encrypted Client Hello (RFC 9849); NIST SP 800-81 Rev. 3 on secure DNS | RFC 9849, NIST |
TCP and UDP in one paragraph each
TCP is a connection oriented byte stream. A three way handshake (SYN, SYN-ACK, ACK) agrees starting sequence numbers, every byte is numbered and acknowledged, lost data is retransmitted and a window limits data in flight. A connection ends with FIN or is torn down at once with a reset (RST). All of that state rides in every segment's header, which is why TCP's header says so much.
UDP is a datagram protocol. RFC 768 describes it as providing "a minimum of protocol mechanism": no handshake, ordering, retransmission or delivery guarantee, just an 8 byte header. Reliability and encryption are the application's job, which is why UDP carries DNS, NTP, VoIP, games and QUIC, which rebuilds both in user space.
What each header field reveals on the wire
The TCP header
RFC 9293 defines the header below. The fixed part is 20 bytes; options can extend it to 60 bytes, because the 4 bit Data Offset field counts 32 bit words.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Acknowledgment Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data | |C|E|U|A|P|R|S|F| |
| Offset| Rsrvd |W|C|R|C|S|S|Y|I| Window |
| | |R|E|G|K|H|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| [Options] |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Here is what an observer learns from each field, even when the payload is encrypted by TLS:
| Field | Size | What it tells an observer |
|---|---|---|
| Source and destination port | 16 bits each | The service (443 for HTTPS, 22 for SSH) and, with the IP addresses, the connection's identity |
| Sequence number | 32 bits | Position in the byte stream, so how many bytes have flowed |
| Acknowledgment number | 32 bits | How much the other side has received, in both directions |
| Data offset | 4 bits | How long the header is, so whether options are present |
| Flags (CWR, ECE, URG, ACK, PSH, RST, SYN, FIN) | 8 bits | Connection setup, teardown and resets; whether congestion signalling is in use |
| Window | 16 bits | Receiver buffer space, a hint about host and load |
| Checksum | 16 bits | Nothing secret, and no protection against deliberate changes |
| Urgent pointer | 16 bits | Rarely used today; RFC 9293 points to RFC 6093, which discourages new applications from using it |
| Options | up to 40 bytes | Maximum segment size, window scaling, selective acknowledgment, timestamps; their presence and order help fingerprint the operating system |
RFC 9293's security section names that last point directly: observations of options, their ordering, packet timing and sizing can identify the host's TCP implementation and operating system. It also cites the "wire image" idea from RFC 8546: TCP's cleartext headers expose more metadata to devices on the path than routing actually needs.
The checksum is often mistaken for an integrity check. RFC 9293 computes it over the header, data and a pseudo header with the IP addresses, to catch misrouted segments. It has no key, so an attacker who rewrites a segment simply recomputes it.
The UDP header
RFC 768 is three pages long and its header is four fields:
0 7 8 15 16 23 24 31
+--------+--------+--------+--------+
| Source | Destination |
| Port | Port |
+--------+--------+--------+--------+
| | |
| Length | Checksum |
+--------+--------+--------+--------+
| data octets ...
+---------------- ...
| Field | Size | What it tells an observer |
|---|---|---|
| Source port | 16 bits | The sending process, and RFC 768 notes it may be assumed to be where a reply should go; it is optional and can be zero |
| Destination port | 16 bits | The service: 53 for DNS, 123 for NTP, 443 for QUIC, 853 for DNS over QUIC |
| Length | 16 bits | The exact size of the datagram including the 8 byte header |
| Checksum | 16 bits | Covers a pseudo header with the IP addresses, the UDP header and the data; an all zero value means the sender computed none |
There is no sequence number, no acknowledgment and no connection. An off-path attacker has nothing to guess at the transport layer except ports, so protection against forged replies must come from the application, and a receiver cannot tell whether a source address is real, which is the root of UDP reflection.
Why both are plaintext by default
TCP and UDP were specified in 1980 and 1981, and encryption was left to the layers above or below. RFC 9293, published in 2022, keeps that split: applications "typically utilize" IPsec below TCP or TLS above it for security. It goes further and says that for full confidentiality, integrity and authentication of TCP connections, including their control flags, "IPsec is the only current effective method." TLS covers the payload, and the TCP Authentication Option (TCP-AO) can authenticate segments on long lived connections such as BGP sessions, but neither encrypts the TCP header.
So on a plain TCP or UDP connection an eavesdropper sees everything. Plain HTTP, classic DNS on port 53, Telnet, FTP and SNMPv1 or v2c all send content in the clear.
On-path versus off-path: who can change what
The protocols defend very differently against the two attacker positions.
| Attacker position | Example | Can read | Can change | What stops them |
|---|---|---|---|---|
| On-path, active | Compromised router, malicious Wi-Fi access point, tampered middlebox | Every header and any unencrypted payload | Anything: drop, delay, rewrite, inject | Only cryptography (TLS, QUIC, IPsec, SSH, WireGuard); they can still block traffic |
| On-path, passive | Tapped link, mirrored switch port, monitoring at a transit network | Every header and any unencrypted payload | Nothing directly, though they may inject from a separate position | Encryption for content; padding and traffic shaping for metadata, partially |
| Off-path | Any host on the internet that is not on your route | Nothing | Only what it can forge blind: guessed sequence numbers, spoofed source addresses | Random ISNs, RFC 5961 checks, source port and ID randomisation, ingress filtering, encryption |
RFC 9001 states the boundary for QUIC: it protects against attackers that cannot read packets but "does not attempt to provide additional protection" against one who can observe and inject during the initial handshake.
What TLS over TCP encrypts, and what it leaves visible
TLS 1.3 was published as RFC 8446 in August 2018. It promises three properties for data after the handshake: the server is always authenticated, data is "only visible to the endpoints", and data "cannot be modified by attackers without detection". Compared with TLS 1.2, RFC 8446 also notes that all handshake messages after the ServerHello are now encrypted, which hides the server's certificate from passive observers.
What still crosses the wire in the clear on a TLS 1.3 connection over TCP:
- IP addresses and ports. These are in the IP and TCP headers, outside TLS.
- The full TCP header on every segment. Sequence numbers, acknowledgments, flags, window and options. RFC 9293 lists TLS as covering "none at all" of the TCP header.
- The ClientHello. It is sent before any keys exist, so it includes the Server Name Indication (SNI), the hostname the client wants, and the Application Layer Protocol Negotiation (ALPN) list, unless Encrypted Client Hello is in use.
- Record sizes and timing. RFC 8446 states that TLS "does not hide the length of the data it transmits", although endpoints may pad records to make lengths less informative. Every encrypted record carries an outer content type of application data (23), which hides the real record type.
What an on-path attacker can change on a TLS connection:
- They cannot read or silently alter encrypted content; a modified record fails authentication and the connection aborts.
- They can forge a TCP reset using sequence numbers read off the wire, and TCP tears down the connection before TLS sees it. TLS closing alerts reveal a truncation but cannot keep the connection alive.
- They can drop, delay or reorder segments, but cannot downgrade a correct TLS 1.3 handshake without detection.
NIST's guidance reflects how central this has become: SP 800-52 Rev. 2 (August 2019) requires US government TLS servers and clients to support TLS 1.2 with approved cipher suites and to support TLS 1.3 by 1 January 2024.
What QUIC over UDP encrypts, and what it leaves visible
QUIC was standardised in May 2021 in RFC 9000 (transport), RFC 9001 (using TLS to secure QUIC) and RFC 8999 (version independent properties). It runs over UDP so it can deploy without kernel or middlebox changes, and RFC 9293 notes that TCP's wire image lessons "have been applied in the design of newer transports like QUIC."
The QUIC short header, after the handshake
Once keys are established, QUIC sends 1-RTT packets with a short header. RFC 9000 defines it as:
1-RTT Packet {
Header Form (1) = 0,
Fixed Bit (1) = 1,
Spin Bit (1),
Reserved Bits (2),
Key Phase (1),
Packet Number Length (2),
Destination Connection ID (0..160),
Packet Number (8..32),
Packet Payload (8..),
}
RFC 9001 section 5.4 explains header protection. A separate key masks the reserved bits, the packet number length, the key phase bit and the packet number itself. That leaves an observer with the header form bit, the fixed bit, the optional spin bit and the destination connection ID. Everything that TCP exposes as transport state (acknowledgments, flow control windows, stream offsets, connection close signals) is carried in encrypted frames inside the payload.
The QUIC long header, during the handshake
Handshake packets use a long header that exposes the QUIC version and both the source and destination connection IDs. RFC 9312, the IETF's guide for network operators, describes what is visible: a client Initial packet exposes the version and both connection IDs without encryption, and the complete TLS ClientHello, including the SNI, travels in CRYPTO frames inside Initial packets.
Initial packets are encrypted, but with keys derived from the visible destination connection ID. RFC 9312 states that an observer can derive SNI "by calculating the Initial secret to decrypt the packet payload", unless the ClientHello is itself encrypted. RFC 9001 adds that Initial packets "are not protected with a secret key" and that some tampering, such as injecting acknowledgments, is not detectable at that stage.
What QUIC still reveals
IP addresses and UDP ports, the fact that it is QUIC, the version and connection IDs, the server name unless Encrypted Client Hello is used, packet sizes and timing, and, if endpoints enable it, the spin bit that lets observers estimate round trip time (RFC 9312).
What a QUIC attacker can change
Because acknowledgments and close frames are encrypted and authenticated, an on-path attacker cannot forge a TCP style reset. QUIC's last resort stateless reset needs a 16 byte token that RFC 9000 calls "hard to guess". An attacker can still drop packets, and some networks block UDP 443, so clients fall back to TCP and TLS.
Encrypted Client Hello closes the SNI gap
The last large leak in both stacks is the hostname in the ClientHello. RFC 9849 (March 2026) defines Encrypted Client Hello (ECH), which encrypts the ClientHello under a public key the server publishes. Support depends on client and server, so check before relying on it. The destination IP address stays visible either way.
TLS over TCP versus QUIC over UDP
| What an on-path observer sees | Plain TCP | TLS 1.3 over TCP | QUIC v1 over UDP | Plain UDP |
|---|---|---|---|---|
| IP addresses and ports | Yes | Yes | Yes | Yes |
| Payload content | Yes | No | No | Yes |
| Transport sequence and acknowledgment numbers | Yes | Yes | No (packet number masked, ACKs encrypted) | Not applicable |
| Connection setup and teardown signals | Yes (SYN, FIN, RST) | Yes (SYN, FIN, RST) | Handshake packet types visible; close is encrypted | Not applicable |
| Server name | In application data, if any | Yes, unless ECH | Yes, unless ECH | In application data, if any |
| Packet sizes and timing | Yes | Yes, padding optional | Yes, padding optional | Yes |
| Can an on-path attacker forge a reset? | Yes | Yes | Only with the stateless reset token | Not applicable |
| Can an on-path attacker alter content undetected? | Yes | No | No | Yes |
The attacks, as concepts
Each attack is described at the level a defender needs, with no packet crafting steps or code.
TCP reset injection
A TCP endpoint aborts a connection when it receives a segment with the RST flag that it believes belongs to that connection. To be believed, the forged reset needs the right four tuple (both addresses and both ports) and a sequence number the receiver will accept.
For an on-path attacker this is trivial, since every field is visible, and TLS cannot prevent it because it sits above TCP.
For an off-path attacker it is a guessing game. RFC 5961 explains the original problem: older stacks accepted any reset whose sequence number fell anywhere inside the receive window, so a blind attacker only had to try one guess per window's worth of sequence space. Long lived connections with predictable endpoints, such as BGP sessions between routers, were the classic targets. RFC 5961 (August 2010) changed the rule: a reset is only accepted if its sequence number exactly matches the next expected value. If it is merely inside the window, the receiver sends a "challenge ACK" back to the real peer, and only a genuine peer, which can see that ACK, can respond with the exact reset.
Sequence number prediction, a short history
The initial sequence number (ISN) chosen at the SYN is what a blind attacker must guess to inject data or complete a forged handshake. RFC 793 suggested a global 32 bit counter incremented roughly every 4 microseconds, which protected against stale segments from old connections but was predictable from the outside.
RFC 6528 records the history. In 1985, Morris described an attack that guessed the next ISN a host would use. The attacker opened an ordinary connection to learn the current counter, silenced a host the target trusted, then sent a forged SYN claiming to come from that trusted host and completed the handshake blind using the predicted number. Combined with address based trust, as used by the old Unix "r" commands and Telnet setups of the time, that was enough to run commands on the target.
The fix arrived in two steps. RFC 1948 (May 1996) proposed adding a keyed hash of the connection's addresses and ports to the clock, so that knowing the ISN of one connection tells you nothing about another. RFC 6528 (February 2012) put that algorithm on the Standards Track. RFC 9293 then absorbed it, requiring that the function "MUST NOT be computable from the outside":
ISN = M + F(localip, localport, remoteip, remoteport, secretkey)
Here M is the 4 microsecond timer and F is a pseudorandom function with a secret key. RFC 6528 is explicit that the real solution to address based trust is cryptographic authentication, not better sequence numbers.
A 2016 USENIX Security paper from researchers at the University of California, Riverside and the US Army Research Laboratory showed that a global rate limit on challenge ACKs, introduced to implement RFC 5961, created a side channel. It let a blind off-path attacker infer whether two hosts were talking and then infer the sequence numbers in use. The authors reported the issue as CVE-2016-5696 and proposed changes to both the specification and implementations. Today the Linux kernel documentation for tcp_challenge_ack_limit notes that a per namespace limit "can allow some side channel attacks" and sets the default to unlimited, relying on per socket limits instead. Non-cryptographic defences move the guessing game; they do not end it.
Session hijacking
Transport level session hijacking means injecting data the receiver accepts as coming from the real peer. On-path against plaintext TCP, the attacker reads the current sequence numbers and inserts segments, for example commands into a Telnet session. Off-path, it needs the guessing described above.
Against TLS, transport level injection only breaks the connection: the injected bytes fail authentication and TLS aborts. That is why the modern meaning of "session hijacking" has moved up the stack, to stolen cookies and tokens. Transport encryption is still the precondition. Without it, the cookies cross the wire in the clear.
UDP spoofing
Because UDP has no handshake, a datagram with a forged source address looks genuine at the transport layer. That enables forged answers to queries (DNS cache poisoning) and responses aimed at a victim (reflection).
Amplification and reflection DDoS
CISA's alert TA14-017A on UDP based amplification attacks describes the pattern. An attacker sends many small requests to public UDP servers with the source address forged to be the victim's. The servers, acting as reflectors, send their responses to the victim. Where a response is much larger than the request, the attack is amplified. CISA measures this with the bandwidth amplification factor (BAF): the UDP payload bytes an amplifier sends in reply, divided by the payload bytes of the request. The alert says a single packet can generate between 10 and 100 times the original bandwidth, and its table includes far higher figures:
| Protocol | Bandwidth amplification factor (per CISA) |
|---|---|
| DNS | 28 to 54 |
| NTP | 556.9 |
| SSDP | 30.8 |
| CharGEN | 358.8 |
| CLDAP | 56 to 70 |
| Memcached | 10,000 to 51,000 |
| Multicast DNS | 2 to 10 |
CISA kept adding vectors: CLDAP and TFTP in December 2017, Memcached in February 2018, WS-Discovery in December 2019. RFC 9000 limits a QUIC server to sending no more than three times the bytes it has received from an address until that address is validated, which caps QUIC's usefulness as an amplifier.
TCP's handshake makes it a poor reflector. Its own problem is the SYN flood, where spoofed SYNs fill the queue of half open connections, documented in RFC 4987 (August 2007).
DNS cache poisoning
Classic DNS runs over UDP port 53, and a resolver accepts the first answer that matches its question. Before 2008, an off-path attacker needed to match the 16 bit transaction ID and, often, a predictable or fixed source port. CERT/CC's note VU#800113, published 8 July 2008, explains the weaknesses: with a properly random 16 bit ID, an attacker needs on average 32,768 attempts, some implementations had weak ID generation, and many resolvers used a fixed source port or even port 53 for every query. Researcher Dan Kaminsky showed how to combine these into a fast, practical poisoning technique, and CERT/CC credits Daniel J. Bernstein with the original idea and implementation of randomised source ports.
The coordinated fix was to randomise the source port of every query. RFC 5452 (January 2009) explains that the port acts as a second ID field "containing up to 16 bits", multiplying the search space. It is still probabilistic: integrity needs DNSSEC, and confidentiality needs encrypted transport.
The defences that work
Encrypt the transport: TLS 1.3 and QUIC
Against an on-path attacker, only encryption protects content. Use TLS 1.3 wherever both ends support it, keep TLS 1.2 only with modern cipher suites, and disable everything older. QUIC, which always uses the TLS 1.3 handshake, also hides the transport state TCP exposes. Neither hides IP addresses or traffic shape.
Protect DNS: DNSSEC and encrypted DNS
These solve different problems and work together.
- DNSSEC (RFC 4033 and companions, March 2005) signs DNS data so a validating resolver can detect forged or altered answers. RFC 4033 is explicit that DNSSEC "is not designed to provide confidentiality". It does not hide which names you look up.
- Encrypted DNS hides queries from on-path observers between the client and the resolver: DNS over TLS on TCP port 853 (RFC 7858, May 2016), DNS over HTTPS (RFC 8484, October 2018) and DNS over QUIC on UDP port 853 (RFC 9250, May 2022). The resolver itself still sees every query, so choose one you trust.
NIST SP 800-81 Rev. 3, published in March 2026, is the current US government deployment guide for securing DNS infrastructure.
Stop spoofed packets at the source: BCP 38
RFC 2827 (BCP 38, May 2000) describes ingress filtering: a network forwards customer packets only if their source addresses belong to that customer. Universal adoption would largely end reflection and blind spoofing, which is why CISA tells providers to "use ingress filtering to block spoofed packets" per BCP 38 and BCP 84. NIST SP 800-189 (December 2019) gives detailed guidance on source address validation for organisations that run their own routing. On a single Linux host, reverse path filtering (rp_filter) applies the same idea to each interface.
SYN cookies
RFC 4987 describes SYN cookies: the server keeps no state for half open connections, encoding what it needs into its SYN-ACK sequence number with a keyed hash and time dependent bits, and rebuilds the connection only when a genuine ACK returns. Common schemes cannot encode every TCP option, and the Linux kernel documentation calls SYN cookies a fallback for queue overflow, not a fix for heavy legitimate load.
Rate limiting
CISA recommends DNS response rate limiting, traffic shaping on UDP services and network level rate limits on public UDP services. On hosts, limit new UDP flows to services you expose and keep kernel limits such as tcp_invalid_ratelimit at their defaults.
Firewall state tracking
A stateful firewall drops packets that do not belong to a known connection: invalid or out of window TCP segments, and UDP replies that match no recent outbound request. CISA lists "stateful UDP inspections" as a first mitigation for reflection. It does not stop an on-path attacker, who sees the real state, but it removes many blind forgeries.
The protocol, the exposure and the fix: a decision table
| Protocol or use | What an eavesdropper sees | What an attacker can change | Fix |
|---|---|---|---|
| Plain HTTP over TCP | Everything: URLs, headers, cookies, content | Content, injected scripts, resets | HTTPS with TLS 1.3 and HSTS |
| TLS 1.3 over TCP | IPs, ports, TCP headers, SNI, sizes, timing | Can reset or block, cannot read or alter content | ECH where available; accept that metadata leaks; IPsec or a VPN if headers must be hidden |
| QUIC over UDP | IPs, ports, version and connection IDs, SNI, sizes, timing | Can drop or block; cannot forge acknowledgments or close frames | ECH where available; keep a TCP fallback |
| Classic DNS over UDP 53 | Every name you query and every answer | Forged answers (cache poisoning) | DNSSEC validation plus DoT, DoH or DoQ to a trusted resolver |
| NTP, SNMP, SSDP, Memcached exposed to the internet | Requests and responses | Abuse as a reflector against others | Remove from the internet, rate limit, restrict to known clients, use SNMPv3 |
| Long lived TCP sessions between routers (BGP) | Session metadata and routing updates | Blind or on-path resets | RFC 5961 behaviour, TCP-AO, filtering of spoofed sources |
| Any service on a network that allows spoofed sources | Not applicable | Spoofed floods and reflection from inside your network | BCP 38 ingress filtering, rp_filter, stateful firewalls |
| Internet facing TCP server under SYN flood | Not applicable | Exhausted half open connection queue | SYN cookies, adequate backlog, upstream filtering |
Step by step: check your own hosts and services
These are defender side checks on systems you own. None of them sends forged traffic.
1. List what is listening, especially on UDP
Every public UDP service is a potential reflector. On Linux:
# TCP and UDP listeners with the owning process
sudo ss -tulpn
# Only UDP listeners
sudo ss -ulpn
On Windows (PowerShell) and macOS:
Get-NetTCPConnection -State Listen | Sort-Object LocalPort
Get-NetUDPEndpoint | Sort-Object LocalPort
sudo lsof -nP -iTCP -sTCP:LISTEN
sudo lsof -nP -iUDP
Anything listening on 0.0.0.0 or :: that does not need to be public should be bound to localhost or firewalled.
2. Check the kernel's TCP and spoofing defences on Linux
# SYN cookies: 1 means sent when the SYN backlog overflows (the documented default)
sysctl net.ipv4.tcp_syncookies
# Reverse path filtering: 1 strict, 2 loose, 0 off (kernel default is 0;
# some distributions enable it at boot)
sysctl net.ipv4.conf.all.rp_filter net.ipv4.conf.default.rp_filter
# Challenge ACK limit (RFC 5961); current kernels default to unlimited
sysctl net.ipv4.tcp_challenge_ack_limit
# Rate limit for duplicate ACKs on invalid segments, in milliseconds (default 500)
sysctl net.ipv4.tcp_invalid_ratelimit
To persist reverse path filtering, add a file under /etc/sysctl.d/, for example 90-net-hardening.conf, then run sudo sysctl --system:
net.ipv4.tcp_syncookies = 1
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
The kernel documentation recommends strict mode to prevent spoofing, and loose mode (2) where routing is asymmetric. Test on one host first: strict mode can drop legitimate traffic on multi-homed machines.
3. Add stateful filtering and UDP rate limits
A minimal nftables input policy for a host that serves HTTPS over TCP and QUIC:
# /etc/nftables.conf (review before loading; this sets a default drop policy)
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
iif "lo" accept
ct state established,related accept
ct state invalid drop
meta l4proto { icmp, ipv6-icmp } accept
tcp dport 22 ct state new accept
tcp dport 443 ct state new accept
udp dport 443 ct state new limit rate 2000/second accept
}
}
Load it with sudo nft -f /etc/nftables.conf from a console session, not over the SSH connection you could lock yourself out of, and inspect it with sudo nft list ruleset. Tune the UDP rate to your real traffic.
4. Confirm TLS 1.3 on your endpoints
# Does the server negotiate TLS 1.3?
openssl s_client -connect your.server.example:443 -tls1_3 -servername your.server.example </dev/null 2>/dev/null | grep -E "Protocol|Cipher"
# Does it still accept TLS 1.0 or 1.1? (These should fail; recent OpenSSL builds may refuse them locally too.)
openssl s_client -connect your.server.example:443 -tls1_1 </dev/null
5. Check DNSSEC validation and encrypted DNS on clients
# The "ad" flag in the reply header means the resolver validated DNSSEC
dig +dnssec ietf.org A | grep -E "flags|status"
# On systemd-resolved hosts, see whether DNS over TLS is in use
resolvectl status | grep -i -E "DNSOverTLS|DNSSEC|Current DNS"
To enable DNS over TLS with systemd-resolved, set DNSOverTLS=yes and a resolver that supports it in /etc/systemd/resolved.conf, then restart the service. Use opportunistic first if you are unsure every network will allow port 853.
6. Look at your own traffic's metadata
Capture a few packets of your own HTTPS session, only on systems you are authorised to monitor:
sudo tcpdump -i any -nn -c 10 'tcp port 443 or udp port 443'
You will see addresses, ports, flags, sequence numbers and lengths for TCP, and addresses, ports and lengths for QUIC, but no readable content.
7. Check the libraries that implement all of this
TLS and QUIC live in libraries inside your applications and images. Find out which versions you run:
openssl version
# Debian or Ubuntu images
dpkg -l | grep -E "libssl|openssl|gnutls|libngtcp2|libnghttp3"
# Alpine images
apk info -v | grep -E "openssl|libssl|gnutls|ngtcp2|nghttp3"
Common mistakes
- Treating the checksum as integrity protection. TCP and UDP checksums have no key. Anyone who changes a packet recomputes them.
- Assuming HTTPS hides where you are going. IP addresses are always visible, and the hostname is visible in the ClientHello unless Encrypted Client Hello is in use.
- Assuming TLS makes a connection unbreakable. An on-path attacker can still forge TCP resets or drop packets. TLS turns tampering into a failed connection, not a protected one.
- Thinking DNSSEC encrypts DNS. It signs answers for integrity. Use DoT, DoH or DoQ for privacy, and DNSSEC validation for authenticity.
- Leaving UDP services open to the world. NTP, SNMP, SSDP, CLDAP and Memcached on public interfaces have all been used as amplifiers, according to CISA.
- Turning on strict reverse path filtering everywhere at once. It drops legitimate traffic on hosts with asymmetric routes. Use loose mode where needed and test.
- Relying on IP addresses as authentication. RFC 6528 is clear that address based trust is the real weakness; sequence number hardening only makes blind attacks harder.
FAQ
Is UDP less secure than TCP?
Neither has security built in, so neither protects confidentiality or integrity on its own. UDP is easier to spoof because it has no handshake, which is why it dominates reflection attacks. TCP's handshake makes blind spoofing harder, but its visible header makes on-path resets easy. Security comes from what you run on top: TLS for TCP, QUIC or DTLS for UDP.
Can someone see my data if I use TCP?
Yes, unless it is encrypted. With TLS they still see addresses, ports, the TCP header, the server name and sizes, but not the content.
What does HTTPS hide from my ISP?
Page content, the URL path and query, cookies and form data. Your ISP still sees the IP addresses, traffic volume and timing, usually the hostname from the ClientHello unless Encrypted Client Hello is used, and every DNS name if you use its resolver unencrypted.
Does QUIC encrypt the transport header?
Mostly. Acknowledgments and other transport frames are encrypted, and header protection masks the packet number, key phase and several bits. The destination connection ID and a few bits stay visible, and handshake packets expose the version and both connection IDs.
What is a TCP reset attack?
It is a forged segment with the RST flag that makes one end abort the connection. On-path attackers can do it easily because they see the sequence numbers. Off-path attackers must guess, and RFC 5961 made that much harder by requiring an exact sequence number match and a challenge ACK otherwise.
What is a UDP amplification attack?
An attacker sends small requests to public UDP servers with the victim's address as the source, and the servers send much larger responses to the victim. CISA lists amplification factors from about 2 for multicast DNS to 556.9 for NTP and 10,000 to 51,000 for Memcached.
How do SYN cookies work?
The server encodes connection state into its SYN-ACK sequence number with a keyed hash instead of storing it. Only a client that received that SYN-ACK can return the matching ACK, so spoofed SYNs cannot fill the queue.
What is BCP 38?
BCP 38 is RFC 2827 (May 2000): networks should drop customer packets whose source addresses are not theirs. It stops spoofed traffic at the source and is the main network level fix for reflection.
Where Safeguard fits
Safeguard does not inspect, capture or filter network traffic, and it does not configure firewalls, kernels or DNS resolvers; nothing in the hardening steps above depends on it. The honest connection is the software that implements these protocols. TLS 1.3, QUIC, HTTP/3 and DNS over HTTPS live in open source libraries inside your applications and container images. Safeguard scans repositories, container images and SBOM files, matches components against vulnerability databases and shows which projects contain a given library and version, so when the next TLS or QUIC library advisory lands you can find every affected image. Our post on using SBOMs to find affected products fast walks through that workflow, and the related hardware posts on Wi-Fi generations and network cards cover the layers underneath TCP and UDP.
Fix it without waiting for upstream
Most of the defences in this post live in operating system kernels and network equipment, which you patch through your vendor or distribution. The encryption that actually protects your data, though, comes from TLS, QUIC and DNS libraries bundled into the applications and images you build, so keeping those dependencies current is part of keeping the wire safe.
Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.
1. Autonomous remediation: pull requests, not tickets
When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation covers eight categories, including dependencies, licenses, security posture and findings. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.
2. Gold Open Source: the safe version in seconds, free
gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds. The safeguard-sh/gold-scan-action GitHub Action can fail a build on a known exploited vulnerability, on any known vulnerability, or never, so a version you have just removed cannot quietly come back in next week's merge.
3. Gold Registry: start from components that are already fixed
registry.safeguard.sh provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs, zero malware and a completed license check, with SLSA L3 or higher provenance, a Sigstore signature and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.
When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. This fork and patch flow is in early access today, so ask which packages it covers before you plan around it.
| Your situation | What to use |
|---|---|
| A fixed version exists | Autonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version |
| You need to know today whether you are affected | Gold Open Source lookup and "Am I affected?" checker, free and without login |
| You want vulnerable versions to stop shipping | The Gold scan GitHub Action in CI, plus Safeguard policies and gates |
| Upstream has no fix yet, or will not ship one | A custom Gold request; fork and patch (early access) |
| You want to start clean on new projects | Pull hardened components and images from Gold Registry |
One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.
See how Safeguard would help
These demos show dependency and SBOM workflows, not network monitoring. You can download Safeguard and follow the CLI docs to try them on your own projects.
This demo sets up the Safeguard runner on your own machine, approves it with its device code and then scans from the terminal. Pointed at a container image for a web service, the same scan lists the TLS, QUIC and HTTP libraries inside it with their versions and any known vulnerabilities, so you know what is really terminating your encrypted connections.
Click through it at your own pace, or open it full screen.
This demo is a real CLI session: install, open the interactive terminal, ask it to fix the lodash CVE in a repository, and watch it read the finding and advisory, ask before each command, move lodash to 4.17.21, run npm install and npm test with approval, and print a summary without pushing anything. The same approve each step flow applies when the package to bump is a TLS or QUIC library pinned in your manifest or base image.
Click through it at your own pace, or open it full screen.
This demo connects Claude to the Safeguard MCP server with OAuth and lets you choose which tools Claude can use. Once connected, you can ask in plain language which of your projects include a particular TLS library version, and get the answer from your own scan data rather than from memory.
Click through it at your own pace, or open it full screen.
Quick check
Your web service uses TLS 1.3 over TCP. Can an attacker on the network path still end a connection?
Yes. TLS protects the content but none of the TCP header, so an on-path attacker who can read the sequence numbers can forge a valid reset and the TCP stack will abort the connection. They still cannot read or silently change the encrypted data. QUIC makes this much harder because its close signals are encrypted and a stateless reset needs a secret token.
Does DNSSEC stop your ISP from seeing which sites you look up?
No. DNSSEC signs DNS answers so a validating resolver can detect forgeries, but RFC 4033 states it is not designed to provide confidentiality. To hide queries from the network path, use DNS over TLS, DNS over HTTPS or DNS over QUIC to a resolver you trust.
Sources
- RFC 9293: Transmission Control Protocol (TCP), August 2022
- RFC 768: User Datagram Protocol, 28 August 1980
- RFC 8446: The Transport Layer Security (TLS) Protocol Version 1.3
- RFC 9000: QUIC, A UDP-Based Multiplexed and Secure Transport
- RFC 9001: Using TLS to Secure QUIC
- RFC 8999: Version-Independent Properties of QUIC
- RFC 9312: Manageability of the QUIC Transport Protocol
- RFC 9849: TLS Encrypted Client Hello, March 2026
- RFC 6528: Defending against Sequence Number Attacks
- RFC 1948: Defending Against Sequence Number Attacks (1996)
- RFC 5961: Improving TCP's Robustness to Blind In-Window Attacks
- RFC 4987: TCP SYN Flooding Attacks and Common Mitigations
- RFC 2827 (BCP 38): Network Ingress Filtering
- RFC 5452: Measures for Making DNS More Resilient against Forged Answers
- RFC 4033: DNS Security Introduction and Requirements
- RFC 7858: DNS over Transport Layer Security
- RFC 8484: DNS Queries over HTTPS (DoH)
- RFC 9250: DNS over Dedicated QUIC Connections
- CISA alert TA14-017A: UDP-Based Amplification Attacks
- CERT/CC Vulnerability Note VU#800113: Multiple DNS implementations vulnerable to cache poisoning
- NIST SP 800-52 Rev. 2: Guidelines for the Selection, Configuration, and Use of TLS Implementations
- NIST SP 800-189: Resilient Interdomain Traffic Exchange, BGP Security and DDoS Mitigation
- NIST SP 800-81 Rev. 3: Secure Domain Name System (DNS) Deployment Guide
- Linux kernel documentation: IP sysctl
- Cao et al., Off-Path TCP Exploits: Global Rate Limit Considered Dangerous, USENIX Security 2016
Last reviewed: 23 October 2026. Encrypted Client Hello support varies by client and server; check your software's documentation before relying on it.