- Severity: major (for any loopback client using
tor-browser-mode) - Location:
onion-grater, functionhandle()around thetor_browser_mode and remote_connectioncheck (Tails master ~line 922), andis_my_stream()(~line 396).
tor-browser-mode is meant to restrict a client to seeing only its own STREAM
and CIRC events, by matching the stream's source address against the client's
address. Stream ownership is decided in is_my_stream():
def is_my_stream(self, stream):
if self.client_pid is not None:
# PID-based matching is racy and inherently insecure,
# so we don't restrict-stream-events for it
return False
if self.client_address[0] == stream.source_address:
return True
return FalseFor a PID-based (loopback) connection, client_pid is set, so
is_my_stream() always returns False -- no stream is ever "owned".
The option is only auto-disabled for remote connections:
if self.tor_browser_mode and remote_connection:
...
self.tor_browser_mode = FalseThere is no equivalent disable for PID-based connections. So if a client that is
matched by apparmor-profiles/users (i.e. a loopback, PID-based connection)
uses a profile with tor-browser-mode: true, the mode stays enabled but
is_my_stream() always returns False. Result: every STREAM event is dropped
and getinfo circuit-status returns no circuits.
- Any loopback client using a
tor-browser-modeprofile gets a non-functional control port for stream/circuit visibility. - In Tails, Tor Browser is the intended consumer; whether it is reached via the PID-based path depends on how it connects.
- Whonix: inert (no Whonix profile enables
tor-browser-mode). It does block enabling stream isolation for a loopback-matched app (e.g. wahay), which would hit exactly this bug.
Disable tor-browser-mode for PID-based connections as well, since they cannot
be source-address matched:
unsupported = remote_connection or pid_based_connection
if self.tor_browser_mode and unsupported:
self.debug_log(
f"filter '{self.filter_name}' has `tor-browser-mode` set "
"but this connection cannot be source-address matched, "
"so the option was disabled"
)
self.tor_browser_mode = False(Or, better, implement PID-based stream ownership so the feature can work for loopback clients -- but the safe minimum is to disable rather than silently drop everything.)
Found by CodeRabbit during an AI-review pass of the Whonix onion-grater resync to Tails, 2026-06.