Problem
The kill switch activates only when a RequestException is raised (__init__.py:72-74):
try:
return super().request(method, url, **kwargs)
except RequestException as e:
self._killed = True
raise ProxyError(f"Proxy failed, kill switch ON: {e}") from e
This design assumes that a failing proxy will always raise an exception. However, there are scenarios where the proxy could silently stop routing traffic through itself without raising any exception:
- Transparent proxy failover — some proxy configurations or network setups may silently fall back to a direct connection if the SOCKS5 handshake fails at the network level but the TCP connection to the destination succeeds via a different route.
- Misconfigured proxy — a proxy that accepts the connection but doesn't actually tunnel the traffic (returns the response directly or via a different path).
- Library behavior changes — future versions of
requests or PySocks could change exception-raising behavior.
In any of these cases, traffic flows directly from the user's real IP, and the kill switch never activates because no RequestException was thrown.
Why check_ip() alone is insufficient
The check_ip() method can detect this scenario, but it must be called manually by the user. There is no automatic, periodic, or per-request IP verification. A user who calls session.get(url) 1000 times without ever calling check_ip() has no protection against silent proxy bypass.
Proposed solution
Option A: Periodic automatic IP check
Add an optional automatic check_ip() call every N requests:
def __init__(self, ..., check_interval: int = 0):
self._check_interval = check_interval
self._request_count = 0
def request(self, method, url, **kwargs):
if self._killed:
raise ProxyError(...)
self._request_count += 1
if self._check_interval > 0 and self._request_count % self._check_interval == 0:
self.check_ip()
# ... proceed with request
Option B: Verify proxy headers on every response
Check for proxy-identifying response headers (e.g., Via, X-Forwarded-For) or verify the connection was actually routed through SOCKS5 at the socket level.
Option C: Document the limitation
At minimum, clearly document that check_ip() should be called periodically by user code, and explain the risk of silent bypass.
Impact
- Severity: High — real IP is exposed with no warning or kill switch activation
- Scope: All users who don't manually call
check_ip() between requests
- Claim affected: "your IP never leaks" is false in this scenario
Problem
The kill switch activates only when a
RequestExceptionis raised (__init__.py:72-74):This design assumes that a failing proxy will always raise an exception. However, there are scenarios where the proxy could silently stop routing traffic through itself without raising any exception:
requestsorPySockscould change exception-raising behavior.In any of these cases, traffic flows directly from the user's real IP, and the kill switch never activates because no
RequestExceptionwas thrown.Why
check_ip()alone is insufficientThe
check_ip()method can detect this scenario, but it must be called manually by the user. There is no automatic, periodic, or per-request IP verification. A user who callssession.get(url)1000 times without ever callingcheck_ip()has no protection against silent proxy bypass.Proposed solution
Option A: Periodic automatic IP check
Add an optional automatic
check_ip()call every N requests:Option B: Verify proxy headers on every response
Check for proxy-identifying response headers (e.g.,
Via,X-Forwarded-For) or verify the connection was actually routed through SOCKS5 at the socket level.Option C: Document the limitation
At minimum, clearly document that
check_ip()should be called periodically by user code, and explain the risk of silent bypass.Impact
check_ip()between requests