This morning I came across another interesting paper submitted at the NDSS Symposium 2026 like the BLERP paper already documented in this forum, but this time challenging the Wi-Fi client isolation that gives us the impression of security. But guess what? Client isolation is not a properly standardized feature of the IEEE 802.11 standards…
So “does client isolation protect clients from attacking each other on Wi-Fi networks as intended, across different implementations?” - this is the question Xin’an Zhou, Juefei Pu, Zhutian Liu, Zhiyun Qian, Zhaowei Tan, Srikanth V. Krishnamurthy (UC Riverside), and Mathy Vanhoef (KU Leuven) tried to answer in this paper: https://www.ndss-symposium.org/wp-content/uploads/2026-f1282-paper.pdf
The tool is available here: GitHub - vanhoefm/airsnitch (updated version) and the paper artifact here: GitHub - zhouxinan/airsnitch
This tool will also be available in the next version of rfswift.io v0.1.4 → so stay tuned!
Context
(source: https://www.ndss-symposium.org/wp-content/uploads/2026-f1282-paper.pdf)
Maybe some people reading this also remember the good old days when we could steal users’ cookies and intercept data just by connecting to a WEP-protected network. We thought those days were behind us, with the introduction of PMK, GTK, and so on.
Nowadays, if you run a Wi-Fi network, whether it’s a home router with a guest network, a hotel hotspot, or a full enterprise deployment, you’ve probably relied on client isolation (a.k.a. AP isolation) to prevent connected clients from attacking each other. It’s the feature that’s supposed to stop a malicious device on your guest network from sniffing or injecting traffic towards other clients.
However, the AirSnitch paper and tools dismantle that assumption. The researchers performed a security analysis of client isolation across Wi-Fi encryption, IP routing, and internal L2 switching, and found that every single router and network they tested was vulnerable to at least one of their attacks. We’re talking full Machine-in-the-Middle capabilities, even against WPA2/3-Enterprise networks that were previously considered safe from insider threats.
The core problem? As mentioned earlier: client isolation was never standardized by IEEE 802.11. Every vendor implements it differently, with ad-hoc rules that leave gaps at different layers of the stack. AirSnitch exploits those gaps.
The tool itself extends the earlier MacStealer from the USENIX Security '23 “Framing Frames” paper. MacStealer only covered port stealing within a single BSSID for downlink interception. Everything else in AirSnitch — GTK abuse, gateway bouncing, cross-BSSID port stealing, uplink interception, broadcast reflection — is new.
3 layers of failure
The authors structured their analysis around three boundaries where client isolation should be enforced but often isn’t:
| Layer | Boundary | What’s checked |
|---|---|---|
| A: Wi-Fi Encryption | Over-the-air frame protection | GTK/PTK key management, shared passphrases |
| B: IP Routing | Gateway/router forwarding rules | L3 packet routing between clients |
| C: L2 Switching | Internal AP bridge/switch | MAC-to-port forwarding tables |
Most vendors only enforce isolation at one of these layers, typically L2, while completely ignoring the others. Even within a single layer, enforcement is often inconsistent across BSSIDs, frequency bands, and guest/main network boundaries.
The different techniques
Below is a complete catalog of every attack primitive introduced or repurposed in the paper. Each one can be used standalone, but the real power comes from chaining them together for full bidirectional MitM.
Abusing GTK: injecting frames via the shared Group Key
In any WPA network, all clients connected to the same BSSID share a Group Temporal Key (GTK), used by the AP to encrypt broadcast and multicast frames. The attacker wraps a unicast IP packet inside a broadcast Wi-Fi frame, encrypts it with the GTK, and spoofs the AP’s MAC address as the transmitter.
In Scapy notation:
Dot11(dst=ff:ff:ff:ff:ff:ff, src=access_point) / IP(dst=victim, src=adversary)
The victim’s device decrypts the frame and delivers the embedded packet to the IP stack, completely bypassing AP-side client isolation, since the frame never passes through AP forwarding logic. Only the client matching the destination IP processes it, so targeted attacks remain possible.
This is similar to the Hole 196 attack, but studied here for the first time in the context of bypassing client isolation. The 2010 Hole196 whitepaper already noted that GTK abuse enables “stealth-mode ARP poisoning” invisible to wired IDS/IPS. Sixteen years later, AirSnitch shows the problem was never fixed, and is now worse, because client isolation gives administrators a false sense of security.
All WPA versions (Personal and Enterprise) are affected.
Concretely, using the tool we can call the airsnitch.py script as follows:
./airsnitch.py wlan2 --check-gtk-shared wlan3 --no-ssid-check [--other-bss|--same-bss]
Vulnerable if both GTK values printed are identical.
Passpoint GTK/IGTK flaws: bypassing “secure” hotspot isolation
Passpoint was specifically designed to address insider attacks on protected hotspots, including the Hole196 class of attacks. Its Downstream Group-Addressed Forwarding (DGAF) Disable feature randomizes the GTK per client during the initial 4-way handshake, which is exactly what AirTight recommended in 2010 (“assign a unique, randomly generated GTK to each client”).
The fix was introduced, except the Passpoint specification forgot to require randomization in the group key handshake, FILS handshake, FT handshake, and WNM-Sleep Response frames. So an attacker just waits for the periodic GTK refresh (which uses the group key handshake) and receives the real, shared GTK. The 2010 recommendation was implemented, but incompletely.
Even worse, the IGTK (Integrity Group Temporal Key, used for broadcast management frame authentication) is never randomized under Passpoint. An attacker can abuse the shared IGTK to craft a WNM-Sleep Response that installs an attacker-controlled GTK on the victim. The Wi-Fi Alliance has since addressed IGTK randomization in Passpoint v3.4, but the GTK gap in other handshakes remains a concern.
Note: IGTK randomization testing is listed as a manual test in the current tool.
Machine-on-the-Side bypass: classic PSK eavesdropping
The well-known attack where an insider with the shared WPA2 passphrase captures the victim’s 4-way handshake, derives their PTK, and can then decrypt and inject traffic over the air. If the victim is already connected, a spoofed deauthentication forces a new handshake. Simple, effective, and a reminder that client isolation with a shared password is fundamentally broken → yet vendors still advertise it as a security feature.
Rogue AP bypass: cloning the AP with shared credentials
Like trying to hijack a user on a captive portal, the attacker creates a clone of the legitimate AP using the shared passphrase. Since client isolation is enforced only on the real AP, the rogue AP has no such restrictions. Even under WPA3 with management frame protection, the attacker can force clients onto the rogue AP by spoofing beacon frames with channel switch announcements.
This doesn’t work against Enterprise networks where per-client credentials and server certificate validation prevent rogue AP association.
Gateway Bouncing: the L3 bypass
Many vendors enforce client isolation at L2 (blocking direct frame forwarding between clients) but completely forget about L3. The attacker sends a packet with the victim’s IP address as destination but the gateway’s MAC address as the L2 destination:
Ethernet(src=attacker, dst=gateway) / IP(src=attacker, dst=victim)
The AP happily forwards it to the gateway (the L2 destination matches), and the gateway routes it right back to the victim (the L3 destination matches). The packet doesn’t get blocked by client isolation because at the MAC/Ethernet layer, it’s addressed to the gateway, not another client. Client-to-client injection achieved, no crypto tricks needed.
All WPA versions (Personal and Enterprise) are affected.
This can be tested using the following command:
./airsnitch.py wlan2 --c2c-ip wlan3 --no-ssid-check [--other-bss|--same-bss]
Vulnerable if you see: >>> Client to client traffic at IP layer is allowed
(source: https://www.ndss-symposium.org/wp-content/uploads/2026-f1282-paper.pdf)
Port Stealing: hijacking the AP’s internal switch
Every BSSID on a Wi-Fi AP maps to a virtual port on the AP’s internal software switch. The attacker connects to a different BSSID than the victim, but uses the victim’s MAC address during association. This triggers the AP’s L2 learning process to remap the victim’s MAC to the attacker’s virtual port. All traffic destined for the victim is now forwarded to the attacker, encrypted with the attacker’s own PTK.
The root cause is a decoupling between L2 forwarding (which port a packet exits from) and cryptographic association (which PTK encrypts it). The AP updates the <MAC, PTK> binding to the latest handshake, regardless of which BSSID it occurred on.
In the worst case, if the attacker connects via an open/unencrypted SSID, traffic that was originally protected by WPA2/3 encryption gets forwarded in plaintext over the attacker’s unprotected BSSID. This was confirmed in real university network tests.
The uplink variant spoofs the gateway’s MAC address while connecting as a wireless client, causing all victim uplink traffic to be redirected to the attacker. Surprisingly, many implementations allow this even when other client-to-client traffic is blocked.
The original MacStealer tool only covered port stealing within a single BSSID for downlink interception. AirSnitch extends it to cross-BSSID, cross-AP, and uplink scenarios. Patching the original MacStealer flaw may ultimately require both APs and clients to implement the “Reassociating STA recognition” extension to IEEE 802.11, while most new AirSnitch issues are implementation/configuration flaws that are easier to fix.
All WPA versions (Personal and Enterprise) are affected.
To test downlink port stealing:
./airsnitch.py wlan2 --c2c-port-steal wlan3 --no-ssid-check --other-bss --server 8.8.8.8
Vulnerable if you see: >>> Downlink port stealing is successful.
Note: --same-bss doesn’t make sense here. Both devices would share the same MAC on the same BSSID and kick each other off.
And for the uplink:
./airsnitch.py wlan2 --c2c-port-steal-uplink wlan3 --no-ssid-check [--other-bss|--same-bss] [--server 1.2.3.4]
Vulnerable if you see: >>> Uplink port stealing is successful.
Unlike downlink, both --same-bss and --other-bss are worth testing here — results vary by vendor.
(source: GitHub - vanhoefm/airsnitch)
Broadcast Reflection: GTK-free injection via the AP (L2)
The attacker crafts a Wi-Fi frame with ToDS=1 and Address 3 set to the broadcast MAC:
Dot11(FCfield="to-DS", addr1=adversary, addr2=AP, addr3=ff:ff:ff:ff:ff:ff)
/ IP(dst=victim, src=adversary)
The AP re-encrypts it with the GTK of the victim’s BSSID before broadcasting to all clients. The embedded payload can contain unicast traffic targeting the victim. Unlike direct GTK abuse, the attacker doesn’t need to know the GTK, the AP does the re-encryption. This works from separate BSSIDs or even open networks.
We can run the following command to test it:
./airsnitch.py wlan2 --c2c-broadcast --no-ssid-check [--other-bss|--same-bss]
Vulnerable if you see: >>> Broadcast Reflection is allowed
Server-Triggered Port Restoration: keeping the uplink relay alive
After stealing the gateway’s port for uplink interception, the attacker needs to periodically restore the correct MAC-to-port mapping so intercepted traffic can actually reach the real gateway. The attacker pre-arranges a fixed transmission schedule with an external server (e.g., one burst every 100ms). Each burst triggers the AP’s L2 learning to temporarily re-associate the gateway MAC with the real uplink port. During that window, queued traffic is forwarded upstream, then the port is re-stolen. A standalone helper script is included in the server_triggered_port_restoration/ directory of the repository.
Client-Triggered Port Restoration: forcing the victim to reclaim its port
To return intercepted downlink traffic via gateway bouncing, the victim’s MAC-to-port mapping must temporarily be correct. The attacker sends GTK-encrypted ICMP Echo Requests to the victim, inducing Echo Replies that cause the AP to rebind the victim’s MAC to its legitimate port.
Inter-NIC Relaying: cross-AP traffic forwarding
For multi-AP enterprise networks, the attacker uses two NICs on the same AP: one spoofing the gateway MAC (uplink interception), one with a random MAC (forwarding). Intercepted traffic is relayed internally between NICs, extending the attack beyond single-AP boundaries to any APs sharing a common distribution switch.
How they chain together: full bidirectional MitM
The individual primitives chain together for a complete attack:
- Downlink interception: Port Stealing (victim’s MAC on a different BSSID)
- Downlink re-injection: Gateway Bouncing / GTK Abuse / Broadcast Reflection
- Uplink interception: Port Stealing (gateway’s MAC on the wireless side)
- Uplink relay: Server-Triggered Port Restoration + Inter-NIC Relaying
In the end-to-end test against a Netgear R8000, the full MitM completed in ~2 seconds. The victim was streaming YouTube and didn’t notice any significant disruption. At 10 Mbps UDP, the system showed only 1.7% loss in ideal conditions and 7% with a wall between attacker and AP.
Even injection-only is impactful: injecting malicious ICMPv6 Router Advertisements can trick a client into using a malicious DNS server, enabling subsequent interception of all IP-based traffic.
Defenses & Mitigations
Because client isolation is not standardized, there’s no one-size-fits-all fix. The authors recommend combining multiple mitigations. Interestingly, several of these echo the Hole196 recommendations from 2010, they just weren’t widely implemented.
1. Document your isolation guarantees
If your product provides a “guest network” or “client isolation” toggle, document what it actually does. Can guest clients talk to each other? Is traffic allowed between guest and main? Are wired devices isolated? Almost no vendor does this properly.
2. Randomize group keys per client
The AP should randomize the GTK during every key-distributing handshake: 4-way, group key, FILS, FT, WNM-Sleep Response, and any future handshake. Essential broadcast traffic (ARP, DHCP) can be handled via L2 multicast-to-unicast conversion (Proxy ARP, ICMPv6 RA conversion).
If your gear doesn’t support per-client randomization, at minimum ensure different VLANs use different group keys.
3. Filter unicast IP in broadcast Wi-Fi frames
Client OSes should drop unicast IP packets inside L2 broadcast/multicast frames. Linux has drop_unicast_in_l2_multicast=1. Other OSes should implement equivalent controls. This directly counters the higher-layer exploit path identified in both Hole196, and AirSnitch.
4. VLANs and firewall rules
VLANs isolate guest from main network. Per-client VLANs enforce within-network isolation. But VLANs alone aren’t enough, you still need randomized group keys per VLAN (both GTK and IGTK) and proper firewall rules at both MAC/Ethernet and IP layers. Don’t forget to isolate broadcast traffic too.
5. MAC spoofing prevention
Block clients from using MAC addresses of internal wired devices (gateway, DNS, DHCP). Prevent simultaneous association of the same MAC to multiple BSSIDs (blocks cross-BSSID port stealing). Optionally allow an allowlist for printers/file servers.
6. IP spoofing prevention
Makes it harder to abuse gateway bouncing for MitM relay.
7. Centralized Wi-Fi decryption and routing
Enterprise controllers that decrypt and route all traffic centrally make attacks harder.
8. Warn on insecure configurations
Vendors should warn when client isolation is enabled on open networks or with shared WPA passwords (no real security benefit). Guest network UIs should prompt to also enable isolation between guest clients.
Resources
- Slides: https://www.ndss-symposium.org/wp-content/uploads/2026-f1282-paper.pdf
- Tools (soon in RF Swift too): GitHub - vanhoefm/airsnitch
I’ll pop some other stuff with the new RF Swift images later ![]()


