Preventing SOCKS bypass
YUME’s SOCKS listener carries only the connections that an application sends to it. It is not a system VPN or a kill switch. A browser can still use direct DNS, QUIC, WebRTC, connectivity checks, or another process for traffic outside the configured proxy path.
Treat browser settings as one layer. Browser flags and preferences change, so verify them against the browser version you deploy. If traffic must fail closed for the whole machine, enforce that in the operating system and review the policy independently.
Browser setup
For Chromium-family browsers, start with a separate profile and route names through the SOCKS proxy:
chromium \
--user-data-dir=/tmp/chromium-yume-profile \
--proxy-server="socks5://127.0.0.1:1080" \
--host-resolver-rules="MAP * ~NOTFOUND , EXCLUDE 127.0.0.1" \
--disable-quic \
--webrtc-ip-handling-policy=disable_non_proxied_udp \
--enable-features=WebRtcHideLocalIpsWithMdns \
--no-pings
This configuration sends HTTP and HTTPS through SOCKS, prevents ordinary local name resolution, disables QUIC’s direct UDP path, and limits non-proxied WebRTC candidates. WebRTC applications may stop working unless they can use a proxied TCP relay. Chromium can remove or rename flags, so an accepted command line is not evidence that every request followed it.
For Firefox, set the SOCKS host and port, then enable remote DNS. Disable HTTP/3 and either disable WebRTC or restrict it to the proxy policy required by your deployment. The relevant preferences include:
network.proxy.type = 1
network.proxy.socks = 127.0.0.1
network.proxy.socks_port = 1080
network.proxy.socks_version = 5
network.proxy.socks_remote_dns = true
network.http.http3.enabled = false
media.peerconnection.enabled = false
network.dns.disablePrefetch = true
network.dns.disablePrefetchFromHTTPS = true
network.prefetch-next = false
Disabling WebRTC is the simpler fail-closed choice when calls and peer-to-peer browser features are not needed. Managed-browser policies are preferable to per-user flags for a maintained deployment.
Verify the route
First confirm that a request explicitly sent through SOCKS exits from the YUME server’s address:
curl --socks5-hostname 127.0.0.1:1080 https://ipinfo.io/ip
Then observe the client host while loading pages. Replace the example server address with the actual YUME endpoint:
sudo tcpdump -n -i any \
'not host 127.0.0.1 and not host 203.0.113.10'
Unexpected DNS, UDP/443, STUN, or direct destination traffic is a bypass. Also test browser startup, shutdown, extension updates, captive-portal checks, WebRTC, IPv4, IPv6, DNS failure, YUME disconnect, and process restart. A single IP-check page does not qualify a route policy.
System-wide enforcement
A system-wide policy should allow the YUME process to reach only its configured server path, allow the required loopback listeners, and reject other outbound traffic. It must cover TCP, UDP, DNS, and IPv6. Network namespaces, a dedicated service account, and nftables or the platform firewall can provide that boundary.
Do not paste a generic firewall recipe into a remote system. Interface names, resolver behavior, service accounts, local networks, management access, and recovery paths differ. Resolve those inputs first, apply the rules through a recoverable console, and test that stopping YUME blocks the protected workload without locking out administration.
On Linux, a client packet adapter routes the whole device through a managed
TUN instead of relying on applications to use SOCKS. It is not yet qualified as
a kill switch, and YUME publishes no qualified full-system firewall
configuration.
Android boundary
The separate Android client runs this library through the C ABI’s
device bridge: its android.net.VpnService interface takes every
IPv4 route, and the library carries each connection and datagram on the kit’s
services. Name lookups go through the tunnel to the resolvers the client
configures. Unless IPv6 is carried, the interface has no IPv6 address or
route, so Android blocks IPv6 while the VPN is up. The transport’s own socket
is protected from the VPN’s routes. When the session is lost, the interface
stays in place and connections wait or are reset while the library
reconnects, so nothing leaves beside the tunnel during the gap.
Device tests on a Pixel 9 Pro running Android 17, against a real yumed,
covered connecting, stopping, reconnecting, a server that stops and returns,
VPN revocation, and Wi-Fi to mobile data and back. When an unmetered network
returns, the client replaces the mobile session so the tunnel stops spending
mobile data; open connections end when the session is replaced. Revocation
returns the app to Idle, ready for another connection. IPv6 was blocked while
the IPv4-only VPN was up. With IPv6 carriage enabled and a server with IPv6
egress, an HTTPS request and a UDP DNS query reached public IPv6 destinations
through the tunnel. With Always-on VPN and Block connections without VPN
enabled, the selected kit reconnected after a reboot and the phone’s unlock,
without opening the app.
Killing the VPN process did not restart it automatically during a 90-second observation, even with Always-on VPN enabled. Opening the app alone left it Idle; connecting again restored the tunnel. Android’s Block connections without VPN keeps traffic blocked while the VPN is absent. Without it, Android routes traffic directly between a stop or process death and the next start. Always-on VPN alone is not that blocking rule: enable both settings to keep traffic from leaving outside YUME.
The Android builds cover arm64-v8a, armeabi-v7a, x86 and x86_64, with Google ML Kit translation excluded by default and a separately built opt-in. Only arm64-v8a has been exercised on this device. Other devices and Android versions, and a signed release APK remain unqualified; an unsigned release build does not close the signed-release gate.