Router-side ARP defenses don’t catch what they don’t see
Published:
For a long time the standard answer to ARP poisoning on the LAN has been “use Dynamic ARP Inspection.” Cisco DAI checks every ARP frame against the DHCP-snooping binding table; offending frames get dropped at the switchport. On more capable APs and home routers there are equivalents: DHCP-snooping ARP filtering, IP-MAC binding, ebtables/arptables on br-lan, MikroTik’s arp=reply-only, Ubiquiti’s “ARP cache poisoning protection”. Every one of them works the same way at heart: catch the malicious ARP as it crosses the bridge.
On Wi-Fi, the malicious ARP doesn’t cross the bridge.
This blog examines which router-side ARP defenses are even in the path against this class of attack, and which mitigations actually intercept the frame. The framing follows from AirSnitch (Zhou et al., NDSS’26); none of the primitives discussed are original to this blog. What I’m trying to add is a clean way to think about why every router-side ARP defense in the standard playbook is architecturally a no-op in this setting.
What AirSnitch showed
AirSnitch’s main result is that “client isolation” on Wi-Fi, the AP-level setting almost every vendor ships under that name, is broken in practice. The crux is the GTK. WPA2/WPA3 networks issue a single Group Temporal Key to every associated client and use it to encrypt broadcast and multicast frames the AP transmits. Every client decrypts those frames against the same key. A client that holds the GTK can also encrypt under it, and any frame it puts on the air with addr1=ff:ff:ff:ff:ff:ff and the from-DS bit set will be accepted by every other client’s NIC as a legitimate group-encrypted frame from the AP.
Zhou et al. work out several attack primitives on top of that observation: forging frames as the AP, redirecting traffic through the attacker, cross-network bouncing, and others. They cover the cryptography, the AP-side filtering some vendors implement, and the upstream mitigations. The paper is worth reading in full.
What this blog adds
AirSnitch already implements both of the building blocks involved here, but as separate diagnostics aimed at a different defense.
The GTK-broadcast injection primitive lives in AirSnitch’s --c2c-gtk-inject path: build a from-DS QoS-Data frame, addr1 broadcast, addr2 BSSID, CCMP-encrypt under the GTK, inject on a monitor interface. The inner payload there is an ICMP echo, sent five times as a one-shot test that answers “does GTK injection work on this network?” Separately, AirSnitch ships a classic ARP-poisoning test that sends a normal to-DS Ethernet ARP through the AP’s bridge. That second test is exactly the path Cisco DAI and DHCP-snooping ARP filtering were designed to block, and on hardened networks it fails by design. AirSnitch’s goal there is to demonstrate the primitives separately; bypassing client isolation, not chaining them into an end-to-end ARP attack.
What this blog points out is what happens when those two halves are combined. Replace the ICMP payload inside AirSnitch’s GTK-encrypted from-DS broadcast with an ARP payload, and the resulting frame is the smallest object that simultaneously:
Bypasses every router-side ARP defense that operates on the bridge (DAI, DHCP-snooping ARP filtering, IP-MAC binding, ebtables/arptables on
br-lan, MikroTikarp=reply-only, UniFi “ARP cache poisoning protection”) because the frame does not cross the bridge in the first place. It goes radio → victim NIC. None of those rules ever fires.Updates the victim’s ARP cache anyway, because the victim’s NIC accepts the frame as a legitimate group-encrypted broadcast from the AP, decrypts at MLME, and hands the inner LLC/ARP up to the IP stack, which processes it as it would any other ARP.
There is nothing cryptographically new here. The CCMP construction is the same encrypt_ccmp AirSnitch uses, from Vanhoef’s own libwifi. The frame format is the same one AirSnitch uses. The GTK extraction goes through the same patched wpa_supplicant. The contribution is the structural observation: AirSnitch’s existing GTK-broadcast envelope, with ARP as the inner payload instead of ICMP, is a clean bypass of the entire family of router-side ARP defenses that an admin would otherwise rely on.
In short: AirSnitch breaks the “are these two clients allowed to talk?” defense at the AP, and to do so it presents GTK-broadcast injection and bridge-side ARP poisoning as separate building blocks. This blog combines those two blocks and applies the result to a different defense category, “is this ARP frame valid?”, as enforced on the router or on the AP’s bridge. Same primitive, different defensive territory, different audience.
The frame
The primitive I’m interested in is the smallest one. Build an ARP reply where:
psrcis the IP I want to claim (the gateway, in the common case).hwsrcis my own MAC, or any MAC the victim’s stack will accept.pdstis the target’s IP.hwdstis the target’s MAC.
Now wrap it in 802.11:
RadioTap()
/ Dot11(type=Data, subtype=QoS-Data,
FCfield=from-DS|protected,
addr1=ff:ff:ff:ff:ff:ff, # broadcast destination
addr2=<AP BSSID>, # transmitter is "the AP"
addr3=ff:ff:ff:ff:ff:ff)
/ Dot11QoS(TID=0)
/ Dot11CCMP(PN=<one ahead of AP>, key_id=<gtk_idx>)
/ <CCMP-encrypted: LLC()/SNAP(0x0806)/ARP(...)>
Encrypt under the shared GTK (NDSS’26 §III). PN one above the AP’s last broadcast, so the receivers’ replay window accepts it. Inject on a monitor virtual interface on the same phy as your associated managed interface.
Every other client on that BSSID’s NIC sees a legitimate AP broadcast. The kernel hands the inner LLC/ARP up the stack. The victim’s ARP cache updates. Done.
The interesting fact for this blog is the path the frame takes. Radio out of my NIC, radio into the victim’s NIC, and that’s it. The AP’s bridge does not see this frame. It was never on the bridge. It was never anywhere except the air between two stations.
Walk the defense list
Here’s the per-defense breakdown.
Cisco DAI / Dynamic ARP Inspection
DAI is a switchport feature. It inspects ARP frames on each access port against the DHCP-snooping binding table and drops any frame whose (IP, MAC, VLAN, port) tuple isn’t in the table. Configuration is ip arp inspection vlan ... and friends.
DAI never fires here. The frame travels from the attacker’s NIC’s radio directly to the victim’s NIC. It isn’t transmitted on any wired switchport, isn’t received on any wired switchport, and doesn’t traverse the AP’s br-lan. There is nothing for the switch to inspect.
DHCP-snooping ARP filter on the AP / router
Same architecture as DAI, just running on the AP itself instead of on an upstream switch. On OpenWrt this is typically a netfilter hook on br-lan, or ebtables rules, or arptables. Some vendors expose this as “ARP cache poisoning protection” (UniFi calls it that explicitly).
These rules trigger on frames crossing the bridge. The malicious frame does not cross the bridge. It’s a wireless data frame addressed as a from-DS broadcast, decrypted by the receiver’s NIC, and never bridged anywhere. The hook can’t fire because the frame never appears at the hook.
You can verify this on OpenWrt by running tcpdump -i br-lan arp while the attack runs. You will see the legitimate ARP traffic on the bridge. You will not see the injected frame. It only ever exists on the wireless side.
IP-MAC binding (TP-Link, MikroTik, others)
IP-MAC binding is the same shape: a list of (IP, MAC) pairs, and frames that violate the list get dropped. Some vendors apply it to ARP only, some apply it to IP forwarding too. The implementation is once again on the bridge or upstream of the bridge, and the comment from the previous section applies verbatim.
MikroTik’s arp=reply-only is in the same bucket: it changes the router’s behavior so the router only answers ARPs corresponding to its known leases. It does not inspect or block ARPs flying between two associated clients on the same SSID, because those ARPs don’t reach the router.
ebtables / arptables on br-lan
The lowest-level form of the same defense, and equally not in the path. ebtables -t filter -A FORWARD matches frames being forwarded across the bridge. ebtables -t filter -A INPUT matches frames destined to the bridge itself. The injected frame is destined to the broadcast group, but it’s a wireless broadcast handled at the receiver’s MLME, not a frame the AP is forwarding. The AP’s bridge is not in the conversation.
MFP / 802.11w
Management Frame Protection comes up sometimes as a defense. It isn’t applicable. MFP signs unicast and broadcast management frames (deauths, action frames, and so on). The injected frame here is a data frame. Data frames are protected by the pairwise key (PTK) for unicast and by the GTK for broadcast. MFP is orthogonal.
AP-side from-DS broadcast filtering that isn’t full DGAF Disable
This is the one category of router-side knob that does land in the right architectural place. Cisco’s “P2P Blocking” on WLC, LANCOM’s “Communication between end devices”, Aruba’s various client-isolation knobs: each of these does something between two clients on the same SSID. On vendors like LANCOM, the AP drops from-DS data frames before forwarding them on the medium, so the victim’s NIC never sees the injected frame. The exact set of frames suppressed varies by vendor. Cisco P2P Blocking ARP-only is a documented option.
These are not generic “client isolation” toggles. The default “client isolation” / “AP isolation” / “wireless isolation” setting on most consumer APs only blocks unicast forwarding between clients. It does not suppress forged from-DS broadcasts, because the AP doesn’t know the broadcast it’s seeing is forged: addr2 says it came from the AP itself.
MACsec to the gateway
MACsec mitigates impact rather than prevents poisoning. Even if the victim’s ARP cache is poisoned, traffic to the gateway is protected end-to-end at L2, so the attacker-as-MITM sees ciphertext. Right answer for high-value paths, expensive to deploy, rare in the wild.
Defenses that actually fire
All of the following actually fire on the malicious frame, because they sit at the right architectural layer.
Per-client GTK randomization (Passpoint DGAF Disable, or vendor equivalents)
The most important one. If every associated client receives a different GTK, a client encrypting under its GTK cannot produce a frame any other client will MIC-verify successfully. The primitive dies at the receiver’s CCMP MIC check. AirSnitch (NDSS’26 §VIII) discusses this in the mitigation section. In practice it is rarely enabled by default; most enterprise SSIDs ship with a shared GTK.
You can detect this from a client by associating twice on two different MACs and comparing the two GTKs you receive. If the bytes match, the network is in scope; if they differ, the primitive is mitigated upstream and there’s nothing useful to do at the over-the-air layer.
Per-BSSID or per-client VLAN
A different broadcast domain means a different group key context for everything that matters. The attacker and victim can no longer share a GTK because they’re not in the same encryption context. Common in enterprise campuses for guest/IoT separation; rare on home networks.
AP Proxy ARP / Hotspot 2.0 DGAF Disable
The AP answers ARP queries for known leases on behalf of the wired side, and drops from-DS group ARP broadcasts because it has no reason to ever emit one. In a network configured this way, the injected frame either gets suppressed at the AP (if the AP enforces it strictly) or is harmless (because the AP also forces the victim’s stack to ignore from-DS ARP).
Endpoint-side ARP hardening
The Linux sysctl net.ipv4.conf.<iface>.arp_accept=0 (the default), combined with an existing cache entry for the spoofed IP, causes the kernel to ignore unsolicited ARP replies that don’t match the existing entry. Windows behaves similarly. Per-host hygiene, but real, and against a target that has talked to the gateway recently it can blunt the primitive. Static ARP entries are the same idea, more brittle and less common.
A note on auto-discovery and the return path
A complete ARP poisoner needs more than the inject primitive. It needs to know the victim’s MAC (auto-discovery) and it needs to keep the victim’s traffic flowing once it has been redirected (the return path).
Auto-discovery is interesting because it goes the other direction across the same architectural boundary. The attacker emits a from-DS ARP request for the victim’s IP. The victim’s NIC accepts it as a legitimate group broadcast and the victim’s IP stack answers. The reply is a normal unicast ARP reply addressed to the attacker. That reply takes the conventional path: victim radio → AP → bridge → AP → attacker NIC. So the bridge sees the reply but never the request. From the perspective of any router-side ARP-validation rule that watches for unsolicited replies or for replies that don’t match a recent request, the reply looks legitimate, because there was a recent request, just not one the bridge ever heard.
The return path is a kernel-NAT problem, not a Wi-Fi problem. Once the victim’s cache is poisoned, redirected traffic arrives at the attacker. Forwarding it through the attacker’s host with MASQUERADE keeps the victim’s session alive. This is the same trick arpspoof has always used. The only Wi-Fi-specific concern is wanting a static ARP entry for the victim on the attacker side, so the attacker’s own ARP cache doesn’t get poisoned by the attack the attacker is running.
Implications
The reason to care about this primitive is the size of the deployment universe it actually affects.
It applies to any WPA2 or WPA3 network where the AP issues a shared GTK to all clients, which is most of them. The attacker only needs to associate as a normal client. That means anyone with the SSID’s credentials: an employee, a contractor, a guest with the Wi-Fi password, an ex-employee whose access was never rotated. No rogue AP, no deauthentication burst, no MFP violation, no control of the AP itself, no 802.1X bypass. The attacker associates the way any other client does, and the rest is over the air under a key the network handed them.
What the primitive enables, once a victim’s ARP cache is poisoned, is everything arpspoof could ever do: HTTP injection, downgrade attempts, captive-portal-style hijacking, DNS redirection, credential capture against anything that doesn’t pin TLS, session theft on cleartext or weakly-bound sessions. The redirect is sustained through a normal kernel-NAT MASQUERADE on the attacker’s side, so the victim doesn’t lose connectivity and notice. The technique is the enabling step. The payload is whatever the attacker wants to do once on path.
Detection is hard for an existing SOC. The injected ARP is a CCMP-encrypted broadcast from the AP’s MAC, indistinguishable on the wire from any other group broadcast the AP transmits. The unicast ARP reply that comes back from the victim looks like an ordinary request/reply pair to any IDS watching the wire, because the matching request was over the air under the GTK and never touched a wired link. Wireless IDS can in principle spot anomalies in PN sequencing or repeated injections under the same key id, but that’s a separate and rarer instrumentation than what most networks deploy.
The strategic implication for an enterprise security program is that bridge-side ARP defenses are sunk costs against this threat model. The ones walked through earlier are not wrong; they are simply in the wrong location relative to this attack. Budget that went into them does not need to be re-spent (they still catch ARP attacks from wired hosts and from misconfigured clients), but it cannot be claimed against the ARP-on-Wi-Fi threat model. That claim has to come from somewhere else, and where it has to come from is the section above on defenses that actually fire.
Auditing your own network
If you administer a Wi-Fi network and want to know which side of the line your AP falls on, the two questions worth answering are:
- Does the AP issue the same GTK to every associated client?
- If yes, is a specific host on that SSID actually reachable via from-DS broadcasts, or does the AP suppress them at the medium?
Both checks can be done from a single associated client, without poisoning anything. I’ve published arpgtk for exactly this:
arpgtk --check-gtk-sharedassociates twice on two virtual managed interfaces and byte-compares the GTKs each association receives. Equal => the AP shares one group key across clients (exposed). Unequal => per-client GTK randomization is in effect (mitigated upstream).arpgtk --verify --target-ip IPsends one CCMP-encrypted from-DS broadcast ARP request under the GTK with a benign 169.254.x.x requestor IP and watches the managed iface for the bridged unicast reply. Reply seen => the primitive is viable against that target. The probe does not poison any cache: a target that records(benign-link-local, our-mac)as a side effect doesn’t shadow any real host on the network.
Source and build instructions: https://github.com/gengstah/arpgtk.
arpgtk is scoped tightly to those two questions. Run it from any associated client, read the verdict, decide whether to enable AP Proxy ARP / per-client GTK / per-BSSID VLAN / endpoint hardening based on what came back. That’s the whole loop.
Takeaways for defenders
If you administer the Wi-Fi side of a network: act on the section Defenses that actually fire above. That’s the prescription.
If you administer the router only: none of this is your problem to fix. The mitigations live on the AP and on the endpoints. The router’s ARP defenses are doing what they were designed to do, and they were never designed for a frame that doesn’t reach them.
References
- Zhou, Pu, Liu, Qian, Tan, Krishnamurthy, Vanhoef. AirSnitch: Demystifying and Breaking Client Isolation in Wi-Fi Networks. NDSS 2026. https://papers.mathyvanhoef.com/ndss2026-airsnitch.pdf
- Schepers, Ranganathan, Vanhoef. Framing Frames / MacStealer. USENIX Security 2023.
- Cisco Catalyst Switch Configuration Guide, Dynamic ARP Inspection.
- IEEE 802.11-2020 §12 (RSNA). CCMP framing and group key handling.
