Web pages and server scripts to reproduce Meta and Yandex localhost channel methods.
- Chrome version 142 (released after our study) implements Local Network Access (LNA) mitigation, which asks user permission for (some) localhost network traffic. For reproducing our results, allow local network access when prompted. Alternatively, disable the
Local Network Access Checksflag underchrome://flags. - Chrome version 141 and lower does not implement LNA and hence should work without issues.
- Brave blocks HTTP and HTTPS methods, as noted in our study.
- Firefox blocks the WebRTC STUN method (but not the WebRTC TURN method).
- Python packages:
flaskflask_corsflask_sockaiortc
.
├── additional-vectors/ # Extra PoC payloads and variants
├── http_https_websocket.py # HTTP/HTTPS/WebSocket test server
├── localhost_channel_methods.html # Page demonstrating the localhost channel methods
├── webrtc_turn.py # WebRTC TURN test server
├── webrtc.py # WebRTC STUN test server
└── README.md
This folder contains varuous web pages and server scripts (.py) that can be used to easily replicate localhost abuse methods without using mobile apps.
localhost_channel_methods.htmlrecreates all five methods of sending an ID from web contexts. (Live demo)- HTTP: Sends requests to localhost over HTTP. Used by Yandex since February 2017 until June 2025 and by Meta since September 2024 until October 2024.
- HTTPS: Sends requests over HTTPS to a domain resolving to 127.0.0.1. Used by Yandex since May 2018 until June 2025.
- WebSocket: Sends data via a WebSocket connection with a server on localhost. Used by Meta from November 2024 to January 2025.
- WebRTC STUN: Sends WebRTC STUN binding requests. Used by Meta from November 2024 to June 2025.
- WebRTC TURN: Sends WebRTC TURN requests without SDP-munging. Implemented by Meta from May 2025 to June 2025.
- Run
python http_https_websocket.py(default HTTP port: 5000). - Open
localhost_channel_methods.htmllocally or visit the hosted version. - Open the Network tab in Chrome DevTools.
- Under HTTP, click Send via HTTP and verify the request in the Network tab.
- Confirm in the terminal that the server received the random number.
- Under WebSocket, click Send via WebSocket and verify the
wsrequest in the Network tab. - Confirm in the terminal that the server received the random number.
To set up HTTPS, configure a loopback domain and certificate (see 🔐 HTTPS Test Domain Setup below).
- After generating and accepting
cert.pemandkey.pem, runpython http_https_websocket.py(default HTTPS port: 5001). - Open
localhost_channel_methods.htmllocally or visit the hosted version. - Open the Network tab in Chrome DevTools.
- Under HTTPS, click Send via HTTPS and verify the request in the Network tab.
- Confirm in the terminal that the server received the random number.
WebRTC STUN binding requests are not visible in DevTools Network; use packet captures (e.g., Wireshark) or chrome://webrtc-internals/ (entries vanish quickly).
- Run
python webrtc.py(default port: 10000). - Open
localhost_channel_methods.htmllocally or visit the hosted version. - Open
chrome://webrtc-internals/in another tab or start packet capture software. - Under WebRTC STUN, click Send via STUN and verify the request in
chrome://webrtc-internals/or the capture tool. - Confirm in the terminal that the server received the random number.
The Send with STUN button uses the Meta method with the original SDP-munging technique; Send with Adapted STUN uses an alternative SDP-munging variant if the first is blocked.
WebRTC TURN requests are not visible in DevTools Network; use packet captures or chrome://webrtc-internals/ (entries vanish quickly).
- Run
python webrtc_turn.py(default port: 10001). - Open
localhost_channel_methods.htmllocally or visit the hosted version. - Open
chrome://webrtc-internals/in another tab or start packet capture software. - Under WebRTC TURN, click Send via TURN and verify the request in
chrome://webrtc-internals/or the capture tool. - Confirm in the terminal that the server received the random number.
- The
webrtc_turn.pyserver shuts down after receiving a request and must be restarted for subsequent tests.
The HTTPS method requires a domain resolving to 127.0.0.1 and matching certificates.
-
Edit the
hostsfile (e.g.,C:\Windows\System32\drivers\etc\hostson Windows,/etc/hostson Linux/macOS) to bind a chosen domain (e.g.,myapp.local) to 127.0.0.1.127.0.0.1 myapp.local
-
Generate the certificate using by running the following command in the folder containing
http_https_websocket.py.:openssl req -x509 -newkey rsa:2048 -nodes -keyout key.pem -out cert.pem -days 365 -subj "/CN=myapp.local" -addext "subjectAltName=DNS:myapp.local"
-
Start the HTTPS server: run
python http_https_websocket.py(default HTTPS port: 5001). -
Visit the domain and port in a browser (e.g.,
https://myapp.local:5001). This will display a warning for the self-signed certificate. -
Click on Advanced and then on Proceed to myapp.local (unsafe) to accept the self-signed certificate.
-
Now you can run the HTTPS method described above.
-
After the tests you can remove the
hostsfile entry you have added in step 1.