fix(trace): bind OTLP/gRPC listener to 127.0.0.1 by default#943
Open
sebastiondev wants to merge 2 commits into
Open
fix(trace): bind OTLP/gRPC listener to 127.0.0.1 by default#943sebastiondev wants to merge 2 commits into
sebastiondev wants to merge 2 commits into
Conversation
The OTLP/gRPC trace listener was binding to 0.0.0.0 by default, exposing the unauthenticated trace service to the network. This allows any host on the same network to inject fake spans or exfiltrate collected trace data (which may contain sensitive attributes like API keys and HTTP headers). Bind to 127.0.0.1 (localhost) by default so the trace listener is only accessible from the local machine. CWE-287
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Bind the OTLP/gRPC trace listener to
127.0.0.1by default instead of0.0.0.0, so a local development tool doesn't unintentionally expose an unauthenticated trace receiver to the entire local network.The issue
planoai trace listenand the in-process collector started byplanoai upcreate a gRPC server viaserver.add_insecure_port(...)(seecli/planoai/trace_cmd.py). The server:_get_tracesJSON query method that returns all collected spans, including HTTP request headers captured by instrumented apps (which commonly containAuthorization, API keys, cookies, etc.)Three places hard-coded the bind host to
0.0.0.0:cli/planoai/trace_cmd.py— thetrace listenCLI defaultcli/planoai/trace_cmd.py—start_trace_listener_background()default (called fromplanoai up)cli/planoai/main.py— the console message printed on startupOn a developer laptop on shared Wi‑Fi (coffee shop, conference, office LAN), any peer on the same network can:
<dev-ip>:4317and calling_get_traces, harvesting headers/tokens captured from the developer's own app traffic.The only precondition is network reachability on the gRPC port — there is no existing auth or framework protection in front of this listener.
The fix
Change the default host from
0.0.0.0to127.0.0.1in all three locations. Thehostparameter remains user-overridable for anyone who deliberately wants to receive traces from another machine. This matches the standard convention for developer-facing local servers (Jupyter, Flask debug, OpenTelemetry collectors, etc.).Tests
test_trace_listen_starts_listener_with_defaultsto assert the new127.0.0.1default.trace_cmdstill passes — thehostparameter is still threaded through unchanged, only the default value moves.Adversarial review
Before submitting, I tried to disprove this. Could existing controls already block LAN access? No —
add_insecure_porthas no auth layer, there's no firewall assumption documented forplanoai, and_get_tracesreturns full span data including captured HTTP headers. Could users who want LAN exposure be broken? Thehostargument is still respected on every code path, so explicitly passing0.0.0.0(or any interface) continues to work; only the unconfigured default changes. Other0.0.0.0occurrences in the repo (egress config incore.py, the obs collector, port-probe inmain.py) are unrelated to this listener and deliberately left alone.CWE-306 (Missing Authentication for Critical Function) / CWE-668 (Exposure of Resource to Wrong Sphere) on a developer-tooling listener. Severity is moderate — it requires local-network adjacency, but no user interaction beyond running the documented command, and the data exposed can include bearer tokens from the developer's own traffic.
Happy to adjust framing or add a
--bindflag note in docs if useful.Submitted by Sebastion — autonomous open-source security research from Foundation Machines. Free for public repos via the Sebastion AI GitHub App.